home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Tool Chest / Testing & Debugging / Mac OS Development Toolkit / Automation Essentials 2.3.0 / Host Automation Folder / LaunchQuit Engine / LaunchQuits.lib < prev    next >
Encoding:
Text File  |  1998-03-19  |  83.2 KB  |  2,333 lines  |  [TEXT/MPS ]

  1. #/****************** This is a full line in MPW printing on an 8.5 x 11, in Courier 9 *******************/
  2. #########################################################################
  3. #########################################################################
  4. ##                     Copyright © Apple Computer, Inc. 1992-1997
  5. ##                                All rights reserved
  6. #########################################################################
  7. #########################################################################
  8. #    
  9. #    Library:        Launchquits.lib
  10. #    
  11. #    Version:        2.1.4
  12. #    Description:
  13. #        This is a library for LaunchQuits. The launch and quit are separated into two 
  14. #        sequences, each with two endpoints and any number of items in between. The 
  15. #        sequences comprise milestones, or items to wait for designated by the term 
  16. #        'awaitDesc', alternating with items to do, designated by the term 'doItem'.
  17. #        
  18. #        A sequence may contain conditional sub-sequences. If an awaitDesc is a list 
  19. #        instead of a descriptor, then the first item in this list is evaluated. If it  
  20. #        is true (i.e present for an awaitDesc or true for a conditional), the rest of 
  21. #        the list executed; if not, the whole list is ignored, and the engine continues 
  22. #        with the next item in the main list as an awaitDesc. The conditional 
  23. #        sub-sequence is used where a sequence branches into several paths 
  24. #        which converge later. The conditional returns true if all items pass or if 
  25. #        it is ignored because the first item failed, and returns false ONLY if the 
  26. #        first item passes and a subsequent item fails.
  27. #        
  28. #        CAUTION: In order to properly handle default sequences, a conditional
  29. #        sub-sequence counts as an awaitDesc, even if it contains doItems. The item
  30. #        following a conditional is always a doItem and is always selected unless the 
  31. #        conditional fails, i.e. it is selected even if conditional was ignored. You 
  32. #        can put an empty string as the doItem after a conditional so it does nothing.
  33. #        
  34. #        The CheckLaunchQuit task is the LQ Engine. It receives a list of test 
  35. #        definitions and other parameters from its caller, usually the LaunchQuit 
  36. #        Script. For each test definition, CheckLaunchQuit calls LaunchApplication,
  37. #        then AppSequence, then LQCustom, then QuitSequence.
  38. #        
  39. #        The LaunchApplication task takes the CPU from where it is now to the 
  40. #        application running in the foreground. If the app is launched in the 
  41. #        background, it is then moved to the foreground. Note: If the application 
  42. #        is already running in the foreground, launching by AgentVUBG will not 
  43. #        move it to the background. 
  44. #        
  45. #        The AppSequence task executes a sequence against a previously launched 
  46. #        application that is in the foreground, verifying each milestone on the 
  47. #        way. The default endpoint is [window t:/≈Untitled≈/ o:1], which is added 
  48. #        automatically if the last item in the sequence is a doItem.
  49. #        
  50. #        The LQCustom task is optional. It is the same for every app. After the 
  51. #        AppSequence task completes without errors, CheckLaunchQuit calls LQCustom.
  52. #        The LQCustom.lib file contains this task, and it may do anything, as long
  53. #        as the app is still running in the foreground when it completes. The 
  54. #        LQCustom task returns true in that case, or false if there were problems.
  55. #        
  56. #        The QuitSequence task takes the CPU from the appName as the front process through 
  57. #        quitting the app, verifying each milestone on the way. See the default endpoint 
  58. #        below. The application must disappear from the process menu for a success, 
  59. #        although the Finder may not become active if the test involves multiple apps.
  60. #        
  61. #        testN := {    testType, 'appName', 'appCreator', 'appFolder', 
  62. #                    {launchParameters}, {theLaunchSequence}, {theQuitSequence}    }
  63. #        launchParameters := 
  64. #                        'FPU':            Skip if target does not have an FPU
  65. #                        '32Bit':        Skip if target is using 32-bit addressing
  66. #                        '68040 Caches':    Skip if target has a 68040 and its caches are on
  67. #                        'QuickTime':    Skip if target is not running QuickTime
  68. #                        'noCreatorLaunch':    Skip if method is 'agentVUFG' or'agentVUBG' and this 
  69. #                                        is present. If method is 'auto' then use 'Find File'. 
  70. #                        'bgLaunchOK':    Skip if method is a background launch and this is not present.
  71. #                                        Most apps are not made to launch into the backgound so you 
  72. #                                        need to qualify each one thouroughly before allowing it.
  73. #                        'UserSkipRequest':    Skip because someone upstairs said so.
  74. #                        'SNConflict':    The application uses network based serial number copy 
  75. #                                        protection. If UsingArbitrator() is true, register the 
  76. #                                        application with the Arbitrator before launching. The 
  77. #                                        Arbitrator will give permission to launch if no other 
  78. #                                        actors have registered first. If they have, wait for one
  79. #                                        minute and try again. If UsingArbitrator() is false, ignore 
  80. #                                        this parameter. 
  81. #                        'PPC':            Skip if target is not a PowerPC
  82. #                        {'bitDepth',{restrictedBitDepths}}:    This parameter tells the LQ Engine not
  83. #                                        to launch if the target bitdepth is not in the list of 
  84. #                                        restricted bitdepths. The possible values are 1, 2, 4, 8, 
  85. #                                        16, and 32. For example, {'bitDepth',{8,16,32}} will not 
  86. #                                        launch unless the target is set to 8, 16 or 32 bits per 
  87. #                                        pixel, corresponding to 256, thousands and millions of 
  88. #                                        colors. The other bitdepths (1,2,4) would be considered 
  89. #                                        "bad" bitdepths and for those, the app would be skipped.
  90. #                                        A "bad" bit depth is one that blocks the application 
  91. #                                            from performing its normal launch sequence. This
  92. #                                            can be a crash, or an alert that asks to change the 
  93. #                                            bit depth or quit. If an alert says "bit depth x will
  94. #                                            work but not as well", and it does not crash, that is 
  95. #                                            not a "bad" bit depth and you should script around it.
  96. #                                        Test defs *should* be executed if the application can 
  97. #                                            handle non-optimal bit depths without crashing or quitting. 
  98. #                                            Use the {'bitDepth',{}} parameter to avoid known crashes and 
  99. #                                            problems that can affect other apps or the system, or
  100. #                                            until you have scripted the non-optimal bit 
  101. #                                            depths with conditionals.
  102. #                                        NORMALLY, APPLICATIONS DO NOT CHANGE THE BIT DEPTH
  103. #                                            OR SWITCH BETWEEN COLORS AND GRAYS.
  104. #                        'MMM':            Skip if app does not launch with Modern Memory Manager on.
  105. #                        'EBBE':            Skip if app crashes with EvenBetterBusError,a system 
  106. #                                            extension to help catch renegade references to NIL.
  107. #                        '68K':            Skip if Target is PPC, i.e., launch only if target is a 68K.
  108. #                                        This parameter should be the first one in a parameter list
  109. #                                        due to some apps won't launch properly otherwise.
  110. #                        'MaxT0':        For Maxwell tier 0 app. Yet to be implemented.
  111. #        
  112. #        exampleAppSequence := { awaitDesc[, doItem][, awaitDesc][, doItem]… }
  113. #            awaitDesc:    descriptor: await_presence
  114. #                        integer: wait this long
  115. #                        list: conditional sub-sequence
  116. #                        string: '': do nothing
  117. #                                other:    log the string as cause of failure and return false
  118. #                        
  119. #            doItem:        descriptor: select
  120. #                        string: '<': select the previous awaitDesc
  121. #                                '>': wait for the previous awaitDesc to disappear
  122. #                                '': do nothing
  123. #                                other:    log the string as cause of failure and return false
  124. #                        list: flexible selector; first item is the actionType, second and on 
  125. #                            contain additional info as defined by the actionType
  126. #                            'type_keys':    2nd item: type_keys() list
  127. #                                            3rd item: optional log as purpose of type_keys List
  128. #                            'fieldSequence':2nd item: list of strings to be typed with a 
  129. #                                                tab after each one, for filling dialog fields
  130. #                            'key_eq':        2nd item: key_eq() string
  131. #                            'move_mouse':    2nd item: move_mouse() list
  132. #                                            3rd item: optional log as purpose of move_mouse List
  133. #                            'fieldSequence':2nd item: list of strings to be typed with a 
  134. #                                                tab after each one, for filling dialog fields
  135. #                            'SFGet':        2nd item: string to type followed by returnKey
  136. #                            'SFPut':        2nd item: string to type followed by returnKey
  137. #                                                if Replace button appears, click it
  138. #                            'SFPutNewName':    2nd item: string to type followed by returnKey
  139. #                                                if Replace button appears, make a random name until
  140. #                                                the replace button does not appear
  141. #                                                                    
  142. #                        
  143. #        theQuitSequence := { awaitDesc[, doItem][, awaitDesc][, doItem]… }
  144. #            awaitDesc:    descriptor: await_presence
  145. #                        list: conditional sub-sequence
  146. #            doItem:    descriptor: select
  147. #                    '<': select the most recent awaitDesc
  148. #                    '': do nothing
  149. #                    string: type it followed by returnKey, select [button t:'Replace'] if it exists
  150. #                    add conditional {[application t:appName],[menuItem t:'Quit' m:'File']} 
  151. #                        as a default endpoint
  152. #    Contains:
  153. #        CheckLaunchQuit()
  154. #        LaunchApplication()
  155. #        CheckLaunchDialog()
  156. #        QuitSequence()
  157. #        AppSequence()
  158. #        LQWaitItem()
  159. #        GetLQWaitItemTimeout()
  160. #        LQDoItem()
  161. #        Quit_Apps()
  162. #        AwaitAppQuit()
  163. #        AcquireApplication()
  164. #        ReleaseApplication()
  165. #        FindFile()
  166. #    
  167. #    History:
  168. #        Date:        By:        Changes:
  169. #        12/15/92    SBR        Created based on script by Al Alamsetty and Alan Masri
  170. #        03/22/94    SBR        Many changes after code review, e.g. new library header
  171. #        06/17/94    GK        (Gary Kratzer) Added PPC launch parameter.
  172. #        11/27/94    SBR        Fix for Radar 1195293 in CheckLaunchQuits(). 
  173. #        04/10/95    SBR        CheckLaunchQuits(): Added Phoenix reporting. Added -1096 error handler. 
  174. #                            Better organization and comments for test def execution.
  175. #                            
  176. #                            LaunchApplication: Extensive modifications to fix Radar problems 
  177. #                            1172264, 1193530. Added check for -1096 launch error. Added 'EBBE' 
  178. #                            launchparam. Changed '68040 caches' skip string to request removal
  179. #                            of the test def.
  180. #                            
  181. #                            QuitSequence: Uses ReleaseApplication().
  182. #                                    
  183. #                            AppSequence: Removed 'restart' selectAction, added better reporting 
  184. #                            for move_mouse and type_keys. Moved code for waitItem and doItem 
  185. #                            into separate tasks. Changed descString from a constructed string 
  186. #                            to the descriptor as it appears in the sequence. Now reports the 
  187. #                            ordinal of the sequence item that failed.
  188. #    
  189. #                            Added AcquireApplication() and ReleaseApplication().
  190. #    
  191. #        08/02/95    SBR        Radar 1270966:    added AwaitAppQuit(), new code in Quit_Apps(),
  192. #                                            changes in QuitSequence()
  193. #                            Radar 1272949:    changes to LQWaitItem()
  194. #                            Radar 1274920:    added GetLQWaitItemTimeout()
  195. #                            Radar 1274921:    AppSequence() default v_level from 5 to 4
  196. #                            Radar 1270963:    changes to QuitSequence()
  197. #                            Radar 1271126:    added 'MMM' skip reason
  198. #                            Radar 1124475:    added 'BitDepth n' skip reason
  199. #                            Radar 1274923:    advise to remove 32-bit unclean apps
  200. #                            Radar 1274930:    'FPU' skip string more descriptive.
  201. #        09/12/96     Masa    LaunchApplication: Added FindFile Launch method
  202. #        09/27/96    BRL        Added SPEC Exception handling
  203. #        10/23/96    Masa    CheckLaunchDialog: added code to improve treatment of unexpected dialogs.
  204. #        10/28/96    Bry/Masa    LaunchApplication: Radar 1124475
  205. #                    Masa/Bry     Radar 1390088    Skip test with inadequate bitdepth
  206. #        10/29/96    Masa    CheckLaunchDialog: fixed matching problem in 'Get static dialog text' code segment.
  207. #                            FindFile: debug.
  208. #        11/08/96    Masa    FindFile: modified await_absence for 'Find File≈'
  209. #        12/02/96     Masa    Radar 1185532:    unexpected dialogs, fixed
  210. #                            Radar 1274812    crash detection through try/catch
  211. #                            Radar 1304881    LQAssist.vu documentation
  212. #                            Radar 1369899    added 'btdepth' 'MMM' 'EBBE' '68K' 'MaxTO'
  213. #                            Radar 1271320    Action 1.0.4 test definition
  214. #                            Radar 1606877    FindFile() search criteria: 'name is'
  215. #                                            instead of 'name contains'
  216. #        12/05/96    Masa    FindFile: Changed logic 'gItemNotFound' to 'gItemFound' to eliminate
  217. #                            misleading comment after 'app not found on selected volume(s)'
  218. #        12/05/96    Masa    Radar 1606877    FindFile() search criteria: 'name is'
  219. #                            LaunchApplication: Changed Logic: gItemNotFound to gItemtFound.
  220. #        12/06/96    Masa    Radar 1610060    Misleading FindFile() message after file not found.
  221. #        12/10/96    SBR        LQDoItem: Changed 'await_absence(previousDesc,,,,6)' to 
  222. #                                    'await_absence(previousDesc,waitTime,,,6)' in .
  223. #                            CheckLaunchDialog: Changed  await_absence(previousDesc to use waitTime instead of default
  224. #        12/10/96  SBR/Masa  FindFile:    Added wait(0,0,0,60) in FindFile() at 'launch' def to ensure option
  225. #                                        key is taken into account.
  226. #                                        Changed '(await_absence([window t:/Find File' to
  227. #                                        '(await_absence([application t:/Find File'
  228. #        12/17/96    Masa    CheckLaunchQuit:    Fix Radar 1378111
  229. #                  SBR/Masa                        Fix Radar 1613887
  230. #        01/30/97    SBR        Deleted older exception code and comments.
  231. #        01/31/97    SBR        Changed AIQ LaunchQuits.vuLib to LaunchQuit Test Defs.vuLib.
  232. #                            Changed 'test case' to 'test def'; 'TC' to 'TD'.
  233. #        01/31/97    SBR        Retired VUAidFKEY after many years of valuable service.
  234. #########################################################################
  235. #########################################################################
  236. Libraries    
  237.     #Clouseau libraries
  238.     "Additions.lib", 
  239.     "Clouseau.lib", 
  240.     "Report.lib",
  241.     "TargetControl.lib",
  242.     "VUAid.lib", 
  243.     "VUAid.tool", 
  244.     
  245.     #SPEC libraries
  246.     "FileTool.vuLib", 
  247.     "Results Express.lib",
  248.     "Globals.lib",
  249.     "TCS.lib",
  250.     "ExceptionHandling.lib",
  251.     
  252.     #Launchquit libraries
  253.     "Arbitrator.vu", 
  254.     "LaunchQuit Test Defs.vulib",
  255.     "Dev Launchquits",
  256.     "LQCustom.lib";
  257.  
  258.  
  259. #########################################################################
  260. #    task    CheckLaunchQuit( testType, RunOnlyTheseTests := {}, SkipTheseTests := {}, 
  261. #                                engineParameters := {}, v_level := 4)
  262. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  263. #    Description:    The test def engine for LaunchQuit Test Defs. Calls 
  264. #                    LaunchApplication() and QuitSequence() to do the real work.
  265. #    Parameters:        testType: maximum testType to execute for this engine run
  266. #                    RunOnlyTheseTests: 
  267. #                        empty list: run all TDs except those in SkipTheseTests 
  268. #                        list of strings: run this subset except those in SkipTheseTests 
  269. #                    SkipTheseTests: never run these, they are likely to stop the run
  270. #                    engineParameters:    Misc items to modify engine behavior
  271. #                    v_level: minimum verbosity level for this task to log itself in detail
  272. #    Returns:        nothing
  273. #    Examples:        CheckLaunchQuit(1,true,{'MacDraw Pro','Swamp Gas'});
  274. #    Assumptions:    VU 2.1
  275. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  276. #    History:
  277. #        11/15/92    SBR        Created
  278. #        05/27/93    SBR        Removed test def list parameter. Now we use gBigTCList global
  279. #        08/12/93    SBR        Removed gBigTCList global. Now we use GetTestDef lookup task.
  280. #        11/10/93    SBR        GetTestDef parameters changed. Removed storeTCHistory; 
  281. #                                the lookup task stores its own history in a private global
  282. #        11/10/93    SBR        Renamed gtcResult to theTestDef because of the above reason;
  283. #                                the lookup task returns only the test def now.
  284. #        11/10/93    SBR        Added support for resumeOffset.
  285. #        11/10/93    SBR        Added EPushHandler/EPopHandler for -1104 errors.
  286. #        03/21/94    SBR        Moved RCloseTest() to occur before Arbitrator disconnect 
  287. #        03/21/94    SBR        Added VUAid('Quit') if launchMethod ~= /VUAid2≈/
  288. #        06/27/94    SBR        Added UnRegisterApplication to launch fail path. It was 
  289. #                            previously only in QuitSequence(), and not done if launch failed.
  290. #        11/27/94    SBR        Fix for Radar 1195293. 
  291. #        04/10/95    SBR        Added Phoenix reporting. Added -1096 error handler. Better
  292. #                            organization and comments for test def execution.
  293. #        12/17/96    SBR/Masa    Fix Radar 1378111
  294. #                    SBR/Masa    Fix Radar 1613887
  295. #        01/30/97     SBR        Retired VUAidFKEY (sniff).
  296. #########################################################################
  297. task    CheckLaunchQuit( testType, RunOnlyTheseTests := {}, SkipTheseTests := {},  
  298.                             engineParameters := {}, v_level := 4)
  299. begin
  300.     global gUsingPhoenix, gLQTCSBeginTime;
  301.  
  302.     ##SBR Debug stuff: checking how much time we waste waiting for things that don't happen
  303. #        global gWastedTime := 0;
  304.     
  305.     AddExceptionHandler(-1100, {TASK EH_CrashRecover, {'CheckLaunchQuit',2,15},0});
  306.     AddExceptionHandler(-1104, {TASK EH_CrashRecover, {'CheckLaunchQuit',2,15},0});
  307.     AddExceptionHandler(-1105, {TASK EH_CrashRecover, {'CheckLaunchQuit',2,15},0});
  308.     AddExceptionHandler(-1096, {TASK EH_CrashRecover, {'CheckLaunchQuit',2,15},0});
  309.     
  310.     if isMember('UsingArbitrator', engineParameters);
  311.     begin
  312.         if not PrepareArbitrator()                # launch the Arbitrator external tool
  313.         begin
  314.             RStatus("Please make sure the Arbitrator external tool is on the host.",1);
  315.             RStatus("If it is there, you may need to re-build the desktop.",1);
  316.             exit;
  317.         end;
  318.     end;
  319.  
  320.     gUsingPhoenix := assoc('Phoenix', engineParameters);    
  321.     if gUsingPhoenix
  322.     begin
  323.         if typeOf(gUsingPhoenix) = 'list'
  324.         begin
  325.             NewMatrix({ { "MatrixName", gUsingPhoenix[2] } });
  326.             
  327.             SuiteStart(gUsingPhoenix[1], , '2.1.1', gUsingPhoenix[2]);
  328.             gUsingPhoenix := true;
  329.         end;
  330.         else if typeOf(gUsingPhoenix) = 'string'
  331.         begin
  332.             SuiteStart(gUsingPhoenix, , '2.1.1');
  333.             gUsingPhoenix := true;
  334.         end;
  335.         else
  336.         begin
  337.             SuiteStart('LaunchQuit Engine', , '2.1.1' );
  338.         end;
  339.     end;
  340.     
  341.     engineStartTime := time_list(_Match([time]));
  342.     
  343.     timers := assoc('timers', engineParameters);
  344.     if timers
  345.     begin
  346.         markTime := engineStartTime;
  347.         if isMember('TDCore',timers) 
  348.             TDCoreTimerOn := true;            #time for each LaunchQuit
  349.         if isMember('mark',timers) 
  350.             markTimerOn := true;            #time for test def (+ overhead)
  351.         timers := true;
  352.     end;
  353.     
  354.     ROpenTest("LaunchQuit Engine");
  355.     
  356.     try
  357.         match[target t:?tName z:?tZone];
  358.     catch theError
  359.         ExceptionDispatcher(theError,,{"Match 1 in CheckLaunchQuit", {testType, RunOnlyTheseTests, 
  360.                                                     SkipTheseTests, engineParameters, v_level}});
  361.     
  362.     firstTDOrdinal := 1;                                # set up skipping/resuming mechanism    
  363.     waitingForName := false;    
  364.     resumeAction := assoc('resumeThisTD', engineParameters);
  365.     resumeOffset := assoc('resumeTDOffset', engineParameters);
  366.     iterateTD := assoc('iterateTD', engineParameters);
  367.  
  368.     GetTestDef := assoc('GetTestDefTask', engineParameters);
  369.     specialParameters := assoc('specialParameters', engineParameters);
  370.     randomDeal := assoc('randomDeal', engineParameters);
  371.     if randomDeal
  372.         nextTDcommand := 'randomDeal';
  373.     else 
  374.         nextTDcommand := 'nextTD';
  375.     doCustomTask := assoc('doCustomTask', engineParameters);
  376.     
  377. #        09/29/94 SBR: Auto-resuming was removed when we switched to the Arbitrator external tool,
  378. #        which does not support the resume feature. One day it may return, but first we have to 
  379. #        define what "resume" means in the larger context of a bundle of tests (a la Tracs).
  380. #    
  381. #        if UsingArbitrator() and resumeAction
  382. #        begin
  383. #            if resumeAction = 'Reset'
  384. #            begin
  385. #                send_list('Arbitrator', {'resumeReset'});
  386. #                if receive_list('Arbitrator', 2, 120) <> { tName,'resumeReset' }
  387. #                begin
  388. #                    RStatus("Arbitrator did not respond to 'resumeReset', so resume feature is off.",1);
  389. #                    resumeAction := false;
  390. #                end;
  391. #            end;    
  392. #            else if resumeAction ~= /Arb≈/                    # Arbitrator returns name of TD to resume
  393. #            begin
  394. #                send_list('Arbitrator', {'resume'});
  395. #                temp := receive_list('Arbitrator', 2, 120);    
  396. #                if temp[1] = tName                            # temp[2] = 'resumeReset' or "{TDName}"
  397. #                begin
  398. #                    resumeAction := temp[2];
  399. #                    if resumeAction = 'resumeReset'
  400. #                        resumeAction := false;
  401. #                    else begin
  402. #                        if resumeOffset
  403. #                            temp := " offset by {resumeOffset}";
  404. #                        else 
  405. #                            temp := "";
  406. #                        RStatus("Resuming script execution at '{resumeAction}'{temp}.",1);
  407. #                        waitingForName := true;
  408. #                    end;
  409. #                end;
  410. #                else 
  411. #                begin
  412. #                    RStatus("Received bad message from Arbitrator ({temp}), so resume feature is off.",1);
  413. #                    resumeAction := false;
  414. #                end;
  415. #            end;
  416. #        end;
  417.     
  418.     #    The next section uses the GetTestDef task reference variable, which is passed to 
  419.     #    the CheckLaunchQuit task through engineParameters. The actual method of storing 
  420.     #    and looking up the test defs is not visible to the caller. It is defined by the
  421.     #    same entity that passes in the GetTestDef value. However, in all cases the task 
  422.     #    parameters and return values are the same. The three parameters are partialName, 
  423.     #    specialParameters, and resetTDHistory.
  424.     #    
  425.     #    PartialName can be the name of the test def, or a specially defined string which 
  426.     #    causes the lookup task to pick a test def in some special way. The three strings 
  427.     #    always available are: 'NextTD', which gets the next test def based on its
  428.     #    privately stored history; 'random', which picks a test def randomly; and 
  429.     #    'randomDeal' which also picks a test def randomly, but uses TDHistory to prevent 
  430.     #    repeating until all of the test defs have been used.
  431.     #    
  432.     #    SpecialParameters is used for any purpose specific to the kind of test defs the
  433.     #    lookup task is looking for. For LaunchQuit Script, use specialParameters to limit 
  434.     #    the search to those test defs whose app parameters list contains all the items in
  435.     #    specialParameters. For example, passing { 'FPU','SNConflict' } in specialParameters
  436.     #    causes the lookup task to search for the first occurance of a test def with both
  437.     #    'FPU' and 'SNConflict' in its app parameters list. The app parameters list is the 
  438.     #    5th item in a LaunchQuit test def, and it may contain other items.
  439.     #        
  440.     #    The resetTDHistory parameter, if true, clears the stored history of the lookup task.
  441.     #    To allow implementation of cool features without additional effort on the caller's 
  442.     #    part, the lookup task stores codes representing the previous test def returned, in
  443.     #    an internally defined global variable. The caller does not need to know the contents 
  444.     #    of this list but it should be documented in the comments of the lookup task. For 
  445.     #    example, when choosing test defs randomly with the LaunchQuit engine, the global 
  446.     #    may contain a list of integers representing applications eligible to be picked. 
  447.     #    This list shrinks over time, but the caller is not aware of this.
  448.     #    If the resetTDHistory parameter contains a list, its value is stored directly into 
  449.     #    the global variable. This a way to test the lookup task as well as begin testing
  450.     #    in the middle of the list.
  451.  
  452.     badResumeMsg := "Could not resume a test def name containing '{resumeAction}'";
  453.  
  454.     RunOnlyTheseIndex := 0;        # get the first test def by name matching, or just get the first one
  455.     if RunOnlyTheseTests
  456.     begin
  457.         if resumeAction            # fixes Radar #1195293
  458.         begin
  459.                 #    look for resume item by exact name (fast but not 100% sure to find it)
  460.             RunOnlyTheseIndex := isMember(resumeAction, RunOnlyTheseTests);
  461.             
  462.             RunOnlyTheseIndex := RunOnlyTheseIndex + resumeOffset;
  463.             if (RunOnlyTheseIndex > card RunOnlyTheseTests) or (RunOnlyTheseIndex = resumeOffset)
  464.             begin
  465.                 RStatus("{badResumeMsg}.",1);
  466.                 RStatus("Please make sure the string in Resume_Last_Run exactly matches",1);
  467.                 RStatus("one of the strings in Run_Only_These_Tests",1);
  468.                 exit;
  469.             end;
  470.  
  471.             resumeAction := false;
  472.         end;
  473.         else
  474.         begin
  475.             RunOnlyTheseIndex := RunOnlyTheseIndex + 1;
  476.         end;
  477.  
  478.         #    get the next test def from the Run_Only_These_Tests list (a script parameter)
  479.         theTestDef := call(GetTestDef, RunOnlyTheseTests[RunOnlyTheseIndex], specialParameters, true);
  480.         ### Masa 12/17/96 Added to fix Radar 1378111
  481.         while (not theTestDef) and (RunOnlyTheseIndex <= card RunOnlyTheseTests)
  482.         begin
  483.             resultString := "∂"{RunOnlyTheseTests[RunOnlyTheseIndex]}∂" not found in the data base; check spelling.";
  484.             rResult('incomplete', resultString);        # report the result of this test def
  485.             RunOnlyTheseIndex := RunOnlyTheseIndex + 1;
  486.             if  RunOnlyTheseIndex <= card RunOnlyTheseTests
  487.                 theTestDef := call(GetTestDef, RunOnlyTheseTests[RunOnlyTheseIndex], specialParameters, true);
  488.         end;
  489.         ### end Radar 1378111 code
  490.     end;
  491.     else 
  492.     begin
  493.         #    get the next test def from the entire database
  494.         theTestDef := call(GetTestDef, nextTDcommand, specialParameters, true);
  495.     end;
  496.  
  497.     while theTestDef                                    # MAIN TEST DEF LOOP
  498.     begin
  499.         if resumeAction                                    # go to the resume TD by name in first iteration
  500.         begin
  501.             theTestDef := call(GetTestDef, resumeAction, specialParameters, true);
  502.             if not theTestDef
  503.             begin
  504.                 RStatus("{badResumeMsg}.",1);
  505.                 exit;
  506.             end;
  507.             
  508.             else for i := 1 to resumeOffset                # fixes Radar 1119463
  509.             begin
  510.                 theTestDef := call(GetTestDef, "nextTD", specialParameters, false);
  511.                 if not theTestDef
  512.                 begin
  513.                     RStatus("{badResumeMsg}, offset by {resumeOffset}.",1);
  514.                     exit;
  515.                 end;
  516.             end;
  517.             resumeAction := false;                        # only use resume feature on first iteration
  518.         end;
  519.  
  520.         thisTestType := theTestDef[1];                    # the type of theTestDef
  521.         appName := theTestDef[2];                        # the application to launch = the test name
  522.         
  523.         skipThisApp := false;
  524.         if SkipTheseTests
  525.         begin
  526.             temp := 1;
  527.             while (temp <= card SkipTheseTests) and not appIsExcepted
  528.             begin
  529.                 shortName := SkipTheseTests[temp];
  530.                 
  531.                 if appName ~= /{shortName}≈/             # is this a TD to skip?
  532.                 begin
  533.                     skipThisApp := true;
  534.                     SkipTheseTests := remove(temp, SkipTheseTests);    # quicker next time
  535.                 end;
  536.                 else temp := temp + 1;
  537.             end;
  538.         end;
  539.             
  540.         if    (thisTestType > testType);                     # reasons to skip this TD without logging
  541.         else for i := 1 to iterateTD                    # OK to continue final checks
  542.         begin
  543. #                if UsingArbitrator()
  544. #                    send_list('Arbitrator', {'beginTD', appName});
  545.             appSig := theTestDef[3];                    # creator (signature) to launch with Agent VU
  546.             appDir := theTestDef[4];                    # parent directory
  547.             launchParams := theTestDef[5];                # modifications/requirements of launch 
  548.             if skipThisApp
  549.                 ### SBR/Masa 12/17/96 Fixed for Radar 1613887
  550.                 launchParams := {'UserSkipRequest'} + launchParams;
  551.             launchSeq := theTestDef[6];                # how to get to a new blank document
  552.             quitSeq := theTestDef[7];                    # how to quit
  553.             
  554.             launchMethod := assoc('launchBy', engineParameters);
  555.  
  556.             if TDCoreTimerOn
  557.                 TDCoreStartTime := _Match([time]);
  558.                 
  559.             ################################################################################
  560.             # Here it is, the big Launch followed by the big Quit. Everything else is fluff.
  561.             
  562.             AddExceptionHandler(-1100, {TASK EH_CrashRecover, {appName,2,15},0});
  563.             AddExceptionHandler(-1104, {TASK EH_CrashRecover, {appName,2,15},0});
  564.             AddExceptionHandler(-1105, {TASK EH_CrashRecover, {appName,2,15},0});
  565.             AddExceptionHandler(-1096, {TASK EH_CrashRecover, {appName,2,15},0});
  566.             
  567.             ##### LAUNCH THE APPLICATION
  568.             LQResult := LaunchApplication(appName, appSig, appDir, launchMethod, launchParams, 10 );
  569.                                             
  570.             ##### DO THE LAUNCH SEQUENCE
  571.             if LQResult[1] = 'pass'                # application passed basic launch
  572.             begin
  573.                 launchMethod := LQResult[2];    # LaunchApplication can use alternate methods
  574.  
  575.                 #default if launch sequence is empty or even number, i.e. no waitItem at the end
  576.                 if not launchSeq or (card launchSeq) = (card launchSeq/2)*2
  577.                     launchSeq := launchSeq + {[window t:/≈Untitled≈/]};
  578.     
  579.                 if AppSequence(appName, launchSeq, false)
  580.                     RAddResult("completed launch sequence");
  581.                 else
  582.                 begin
  583.                     theTarget := _Match([target]);
  584.                     if not theTarget
  585.                         moreAddResult := " - target crashed";
  586.                     else 
  587.                         moreAddResult := '';
  588.                     
  589.                     RAddResult("failed launch sequence {moreAddResult}");
  590.                     LQResult := {'fail',"'{appName}' failed during the launch sequence"};
  591.                 end;
  592.             end;
  593.  
  594.             ##### DO THE CUSTOM TASK
  595.             if (LQResult[1] = 'pass') and doCustomTask     # application passed launch sequence
  596.             begin
  597.                 theResult := LQCustomTask();            # see LQCustom.lib
  598.                 if theResult
  599.                     RAddResult("The custom task executed correctly.");
  600.                 else 
  601.                 begin
  602.                     RAddResult("The custom task did not execute correctly.");
  603.                     LQResult := {'fail',"'{appName}' failed during the custom task"}; 
  604.                 end;
  605.             end;
  606.  
  607.             ##### QUIT THE APPLICATION
  608.             if LQResult[1] = 'pass'                        # custom task passed (if it was called)
  609.             begin
  610.                 quitResult := QuitSequence(appName, quitSeq);
  611.  
  612.                 if (quitResult[1] = 'pass')             # everything worked!!
  613.                     LQResult:= {'pass',"{appName} LaunchQuit by {launchMethod}"};
  614.                 else 
  615.                     LQResult := quitResult; 
  616.             end;
  617.                 
  618.             ##### CHECK FOR FAILURE
  619.             switch LQResult[1]
  620.             begin
  621.                 case 'pass':
  622.                 begin
  623.                     tcPassed := true;
  624.                 end;
  625.                 
  626.                 case 'incomplete':
  627.                 begin
  628.                     tcPassed := false;
  629.                     # No need to un-register because it was skipped
  630.                 end;
  631.                 
  632.                 case 'fail':
  633.                 begin
  634.                     tcPassed := false;
  635.                     Quit_Apps({appName},false);            # quit this app any possible way
  636.     
  637.                     if UsingArbitrator()
  638.                     begin
  639.                         # Un-register the app for SNConflict. If we are using the Arbitrator at all, 
  640.                         # we send every app name to ReleaseApplication() and let that task decide for 
  641.                         # us if the application is registered or not. We do this because the actual 
  642.                         # registration mechanism may change, so keep it in wrapper tasks.
  643.                         # If the app was not registered, ReleaseApplication() returns true.
  644.                         
  645.                         if not ReleaseApplication( appName )
  646.                             return {'incomplete', 'CheckLaunchQuit (fail): ReleaseApplication failed.'};
  647.                     end;
  648.                 end;
  649.             end;
  650.  
  651.             RemoveExceptionHandler(-1104);
  652.             RemoveExceptionHandler(-1100);
  653.             RemoveExceptionHandler(-1105);
  654.             RemoveExceptionHandler(-1096);
  655.             ################################################################################
  656.                         
  657.             timerString := "";
  658.             if timers
  659.             begin
  660.                 if TDCoreTimerOn 
  661.                     timerString := "(" + time_str( time_sub(_Match([time]), TDCoreStartTime) ) + 
  662.                                     timerString + ") ";
  663.                         
  664.                 if markTimerOn
  665.                 begin
  666.                     markTimeInterval := time_sub(_Match([time]), markTime);
  667.  
  668.                     markTime := time_add(markTimeInterval,markTime);
  669.                     timerString := "(" + time_str( markTimeInterval ) + timerString + ") ";
  670.                 end;
  671.             end;
  672.  
  673.             # If we did not skip, check if there is a MacsBug macro set up. If there  
  674.             # is, then always look for a crash log even if the test "passed". If the 
  675.             # test failed or if a crash log exists, log a full report, and   
  676.             # reset the EveryTime macro. Otherwise just print the "verified" line.
  677.             
  678.             if not (LQResult[2] ~= /≈skip≈/)
  679.             begin
  680.                 if setMacsBugMacro('read')
  681.                 begin
  682.                     mbLogName := MacsBugLog(appName);
  683.                     if mbLogName
  684.                     begin
  685.                         RAddResult("MacsBug log is named {mbLogName}");
  686.                         setMacsBugMacro('restore');
  687.                         if tcPassed
  688.                             LQResult:= {'fail',"{appName} LaunchQuit passed, but found a MacsBug Log"};
  689.                         tcPassed := false;
  690.                     end;
  691.                 end;
  692.             end;
  693.  
  694.             if gUsingPhoenix
  695.             begin
  696.                 _Match([mouse]);    
  697.  
  698.                 TCSDuration := LastCommandTargetTime() - gLQTCSBeginTime;
  699.  
  700.                 switch LQResult[1]
  701.                 begin
  702.                     case 'pass':
  703.                     begin
  704. #                        TCSEnd(pTCSId := {}, pResultCode := '', pErrStr := '', pTCSVal := 0, pTCSStr := '', pCommentStr := '', pExceptionFlag := '')
  705.                         TCSEnd({ launchTCSNumber, global kTCSetLaunch }, 1,,TCSDuration,appName,LQResult[2]);
  706.                     end;
  707.                     case 'fail':
  708.                     begin
  709.                         TCSEnd({ launchTCSNumber, global kTCSetLaunch }, 0, LQResult[2],TCSDuration,appName);
  710.                     end;
  711.                     case 'incomplete':
  712.                     begin
  713.                         TCSEnd({ launchTCSNumber, global kTCSetLaunch }, -1, LQResult[2],TCSDuration,appName); 
  714.                     end;
  715.                 end;
  716.             end;
  717.         
  718.             LQResult := { LQResult[1], "{timerString}" + LQResult[2] };    # add timer info
  719.             
  720.             if not tcPassed 
  721.                 RPushVerbosity(3);
  722.             rResult(LQResult[1], LQResult[2]);            # report the result of this test def
  723.             if not tcPassed 
  724.                 RPopVerbosity();
  725.             
  726.         end;    # for i := 1 to iterateTD (implies theTestDef[1] <= testType)
  727.  
  728.         if RunOnlyTheseTests        # get the next test def by name matching, else just get the next one
  729.         begin
  730.             RunOnlyTheseIndex := RunOnlyTheseIndex + 1;
  731.             
  732.             if RunOnlyTheseIndex <= card RunOnlyTheseTests
  733.             begin
  734.                 #    get the next test def from the Run_Only_These_Tests list (a script parameter)
  735.                 theTestDef := call(GetTestDef, RunOnlyTheseTests[RunOnlyTheseIndex], 
  736.                                     specialParameters, true);
  737.                 ### Masa 12/17/96 Added to fix Radar 1378111
  738.                 while (not theTestDef) and (RunOnlyTheseIndex <= card RunOnlyTheseTests)
  739.                 begin
  740.                     resultString := "∂"{RunOnlyTheseTests[RunOnlyTheseIndex]}∂" not found in the data base; check spelling.";
  741.                     rResult('incomplete', resultString);        # report the result of this test def
  742.                     RunOnlyTheseIndex := RunOnlyTheseIndex + 1;
  743.                     if  RunOnlyTheseIndex <= card RunOnlyTheseTests
  744.                         theTestDef := call(GetTestDef, RunOnlyTheseTests[RunOnlyTheseIndex], specialParameters, true);
  745.                 end;
  746.                 ### end Radar 1378111
  747.             end;
  748.             else 
  749.                 theTestDef := {};            
  750.         end;
  751.         else 
  752.         begin
  753.             theTestDef := call(GetTestDef, nextTDcommand, specialParameters, false);
  754.         end;
  755.     end;    # while theTestDef                            # MAIN TEST DEF LOOP
  756.  
  757.     ##SBR Debug stuff
  758. #        global gWastedTime;
  759. #        println ;
  760. #        println "        ••Wasted {gWastedTime} seconds in conditional sub-sequences!••";
  761. #        println ;
  762.  
  763.     RCloseTest();
  764.     
  765.     if UsingArbitrator()                                # clean disconnect from the Arbitrator
  766.     begin
  767. #            send_list('Arbitrator', {'resumeReset'});
  768. #            receive_list('Arbitrator', 2, 60);
  769.         ReleaseArbitrator();
  770.     end;
  771.     
  772.     if launchMethod ~= /VUAid2≈/                         # quit the external tool if we used it
  773.         VUAid('Quit');
  774.     
  775.     RemoveExceptionHandler(-1104);
  776.     RemoveExceptionHandler(-1100);
  777.     RemoveExceptionHandler(-1105);
  778.     RemoveExceptionHandler(-1096);
  779.  
  780.     if gUsingPhoenix
  781.     begin
  782.         SuiteEnd(1);
  783.     end;
  784. end;
  785.  
  786.  
  787. #########################################################################
  788. #    task            LaunchApplication(    appName, appSig, appDir, launchBy, 
  789. #                                        launchParams, v_level)
  790. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  791. #    Description:    Launch an application by a particular method, unless the target 
  792. #                    is not capable of it. Use special parameters to ensure the application 
  793. #                    launches only under the right conditions.
  794. #    Parameters:        appName:        Exact name of the application to launch.
  795. #                    appSig:            The creator or signature of the application.
  796. #                    appDir:            Exact name of the application's folder.
  797. #                        CAUTION:    Across all volumes on the target, these three values 
  798. #                                    should be unique, to insure zero probability that the
  799. #                                    wrong files are launched, under all conditions. Other 
  800. #                                    Findable items should not contain their names. If appSig
  801. #                                    is not unique, you need to put 'noCreatorLaunch' in 
  802. #                                    launchParams to prevent launching the wrong application.
  803. #                    launchBy:        Method to use for launching
  804. #                        'AgentVUFG':    Launch by creator into the foreground using Agent VU.
  805. #                            CAUTION:     Agent VU 2.0, 2.0.1 and 2.1 will not launch an app if 
  806. #                                        the preferred size is not available. Since Agent VU 
  807. #                                        uses the creator, appSig should be unique across all 
  808. #                                        target volumes.
  809. #                        'AgentVUBG':    Launch by creator into the background using Agent VU. 
  810. #                                        Since most applications do not launch properly into 
  811. #                                        the background, this method is not allowed unless 
  812. #                                        launchParams contains 'bgLaunchOK'.
  813. #                        'Find File':    Launch Find File and find appName. Uses option-
  814. #                                        doubleClick to quit Find File before launching the app.
  815. #                                        This method is sure if the names are unique.
  816. #                        'Finder':        Twitch to Finder and Find appName. Type command-O 
  817. #                                        while pressing the option key to close appDir window.
  818. #                                        This method is slow but sure if the names are unique.
  819. #                        'auto':            Use 'agentVUFG', but if this is fails use 'Find File'.
  820. #                                        Failures are: launchParams contains 'noCreatorLaunch',
  821. #                                        Agent VU fails to locate the application, Agent VU
  822. #                                        fails to launch due to lack of space.
  823. #                        'VUAid2FG':        Launch by appName into foreground using VUAid External tool.
  824. #                        'VUAid2BG':        Launch by appName into background using VUAid External tool. 
  825. #                        'VUAidFKEY':    (Obsolete method; do not use) Use the VUAid FKEY to launch by appName
  826. #                            CAUTION:     As of version 1.0.9, the VUAid FKEY does not return an 
  827. #                                        error if the application does not have enough memory
  828. #                                        space to launch. It returns an error if it can not find
  829. #                                        the application by name, however.
  830. #                    launchParams:        reasons to skip or modify launching and log the reason
  831. #                        'FPU':            Skip if target does not have an FPU
  832. #                        '32Bit':        Skip if target is using 32-bit addressing
  833. #                        '68040 Caches':    Skip if target has a 68040 and its caches are on
  834. #                        'QuickTime':    Skip if target is not running QuickTime
  835. #                        'noCreatorLaunch':    Skip if method is 'agentVUFG' or'agentVUBG' and this 
  836. #                                        is present. If method is 'auto' then use 'Find File'. 
  837. #                        'bgLaunchOK':    Skip if method is 'agentVUBG' and this is not present.
  838. #                                        Most apps are not made to launch into the backgound so you 
  839. #                                        need to qualify each one thouroughly before allowing it.
  840. #                        'UserSkipRequest':    Skip because someone upstairs said so.
  841. #                        'SNConflict':    The application uses network based serial number copy 
  842. #                                        protection. If UsingArbitrator() is true, register the 
  843. #                                        application with the Arbitrator before launching. The 
  844. #                                        Arbitrator will give permission to launch if no other 
  845. #                                        actors have registered first. If they have, wait for one
  846. #                                        minute and try again. If UsingArbitrator() is false, ignore 
  847. #                                        this parameter. 
  848. #                        'PPC':            Skip if target is not a PowerPC
  849. #                        {'bitDepth',{restrictedBitDepths}}:    This parameter tells the LQ Engine not
  850. #                                        to launch if the target bitdepth is not in the list of 
  851. #                                        restricted bitdepths. The possible values are 1, 2, 4, 8, 
  852. #                                        16, and 32. For example, {'bitDepth',{8,16,32}} will not 
  853. #                                        launch unless the target is set to 8, 16 or 32 bits per 
  854. #                                        pixel, corresponding to 256, thousands and millions of 
  855. #                                        colors. The other bitdepths (1,2,4) would be considered 
  856. #                                        "bad" bitdepths and for those, the app would be skipped.
  857. #                                        A "bad" bit depth is one that blocks the application 
  858. #                                            from performing its normal launch sequence. This
  859. #                                            can be a crash, or an alert that asks to change the 
  860. #                                            bit depth or quit. If an alert says "bit depth x will
  861. #                                            work but not as well", and it does not crash, that is 
  862. #                                            not a "bad" bit depth and you should script around it.
  863. #                                        Test defs *should* be executed if the application can 
  864. #                                            handle non-optimal bit depths without crashing or quitting. 
  865. #                                            Use the {'bitDepth',{}} parameter to avoid known crashes and 
  866. #                                            problems that can affect other apps or the system, or
  867. #                                            until you have scripted the non-optimal bit 
  868. #                                            depths with conditionals.
  869. #                                        NORMALLY, APPLICATIONS DO NOT CHANGE THE BIT DEPTH
  870. #                                            OR SWITCH BETWEEN COLORS AND GRAYS.
  871. #    
  872. #                    v_level:        verbosity level for log output
  873. #    Returns:        success: true
  874. #                    failure: {'incomplete', "Skipped '{appName}' - {skipReason}"}
  875. #    Example:        LaunchApplication('TeachText 7.0@', 'ttxt', 'TeachText 7.0ƒ');
  876. #                    LaunchApplication('ResEdit™ 2.1.1@', 'RSED', 'ResEdit™ 2.1.1ƒ','auto',
  877. #                                        {'noCreatorLaunch'})
  878. #    Assumptions:    VU 2.1.
  879. #                    CloseView is removed entirely and never used, otherwise cmd-opt-O
  880. #                    will not work. This is used to launch applications in the Finder.
  881. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  882. #    History:
  883. #        ??/??/92     SBR        Created as launchSequence
  884. #        10/10/93     SBR        Changed to LaunchApplication, removed sequence handler
  885. #        06/17/94     GK        Added PPC launch parameter.
  886. #        11/11/94     SBR        Changed launchparam check to use a case statement.
  887. #        04/10/95     SBR        Extensive modifications to fix Radar problems 1172264, 1193530.
  888. #                            Added check for -1096 launch error. Added 'EBBE' launchparam.
  889. #                            Changed '68040 caches' skip string to request TD removal.
  890. #        08/03/95     SBR        Added Phoenix reporting.
  891. #                            Radar 1274923: '32Bit' skip string requests TD removal.
  892. #                            Radar 1274930: 'FPU' skip string more descriptive.
  893. #                            Radar 1271126: add 'MMM' skip string.
  894. #                            Radar 1124475: add 'Bitdepth n' skip string.
  895. #        09/12/96     Masa    Added FindFile w/exception handling
  896. #        10/23/96    Masa    improved unexpected dialog treatment
  897. #        10/28/96    Bry/Masa    Radar 1124475
  898. #        12/05/96     Masa    Changed Logic: gItemNotFound to gItemFound
  899. #        12/20/96     SBR        Changed Logic: wait until just before launch to call AcquireApplication()
  900. #        01/30/97     SBR        Removed "appDir" code in Find File logic
  901. #        01/30/97     SBR        Retired VUAidFKEY (sniff).
  902. #########################################################################
  903. task LaunchApplication(    appName, appSig, appDir, launchBy, launchParams, 
  904.                             appWait := 10, v_level := 4)
  905. begin
  906.     global    gUsingPhoenix, gLQTCSBeginTime;
  907.     global    kTCSetLaunch;
  908.     
  909.     global  gItemFound;
  910.     global  gDialogWindow;
  911.     global    gOtherUnexpectedFlag;
  912.     
  913.     kQuitWait := 30;
  914.     
  915.     badLaunch := {'fail',"'{appName}' did not launch properly"};
  916.  
  917.     noCreatorLaunch := isMember('noCreatorLaunch',launchParams);
  918.     if noCreatorLaunch
  919.         launchParams := Remove(noCreatorLaunch, launchParams);
  920.         
  921.     if launchBy = 'auto'
  922.     begin
  923.         if noCreatorLaunch
  924.         begin
  925.             launchBy := 'Find File';
  926.         end;
  927.         else 
  928.             launchBy := 'agentVUFG';
  929.     end;
  930.     
  931.     launchTCSNumber := isMember(launchBy, {'AgentVUFG', 'AgentVUBG', 'Finder', 'VUAid2FG', 'VUAid2BG', 
  932.                                             'VUAidFKEY', 'Find File'});
  933.  
  934.     if not launchTCSNumber or launchBy = "VUAidFKEY"
  935.     begin
  936.         RAddResult("'{launchBy}' is an invalid or obsolete launch method.");
  937.         return badLaunch; 
  938.     end;
  939.     
  940.     curApName := _Match([application]).t;                    # to check for wrong app/BG switch
  941.     if launchBy ~= /≈BG/ 
  942.     begin
  943.         try
  944.             match [menu o:$menuOrds];
  945.         catch theError
  946.             ExceptionDispatcher(theError,,{"Match 1 in LaunchApplication()", {appName, appSig, appDir, 
  947.                                             launchBy, launchParams, appWait, v_level}});
  948.  
  949.         processMenu := card menuOrds;
  950.  
  951.         try
  952.             match [menuItem m:processMenu t:$curApList]!;    # store current items in process menu
  953.         catch theError
  954.             ExceptionDispatcher(theError,,{"Match 2 in LaunchApplication", {appName, appSig, appDir, 
  955.                                             launchBy, launchParams, appWait, v_level}});
  956.     end;
  957.  
  958.     if gUsingPhoenix
  959.     begin
  960.         launchTCSNumber := launchTCSNumber + 4;                # SPEC libs use 1-4 already
  961.         gLQTCSBeginTime := LastCommandTargetTime();            # start TCS duration ( >= LQ duration )
  962.         TCSStart({ launchTCSNumber, kTCSetLaunch }, 
  963.                     "LaunchQuit application by {launchMethod}");
  964.     end;
  965.  
  966.     #don't launch if the parameters are not met (or wait if SNConflict)
  967.     skipReason := '';
  968.     arbResponse := '';
  969.     #SBR 12/20/96 Changed for Radar 1615038
  970.     SNConflict := false;
  971.     
  972.     # look for special restrictions or modifications for launch
  973.     try
  974.     begin
  975.         # Added for Radar 1124475
  976.         restrictedBitDepths := assoc('bitDepth', launchParams);
  977.         if restrictedBitDepths
  978.         begin
  979.             curDepth := get_target_info('bit depth#');
  980.             if not isMember(curDepth, restrictedBitDepths)
  981.                 throw "Current bitDepth ({curDepth}) is unacceptable. Only {restrictedBitDepths} are allowed.";
  982.         end;
  983.         for each launchParam in launchParams
  984.         begin
  985.             switch launchParam
  986.             begin
  987.                 case 'FPU':
  988.                 begin
  989.                     if not get_target_info('fpu#')
  990.                     begin
  991.                         # better string for Radar 1274930
  992.                         skipReason := "680x0 FPU required";
  993.                         if get_target_info('processor') ~= /PPC≈/
  994.                             skipReason := skipReason + " (software FPU needed on PowerPC)";
  995.                         throw skipReason;
  996.                     end;
  997.                 end;
  998.                 
  999.                 case 'UserSkipRequest':
  1000.                 begin
  1001.                     throw "user request";
  1002.                 end;
  1003.                 
  1004.                 case 'PPC':
  1005.                 begin
  1006.                     if not (get_target_info('processor') ~= /PPC≈/)
  1007.                         throw "PowerPC processor required (will not run on 680x0)";
  1008.                 end;        
  1009.                 
  1010.                 case '68K':        # SBR 02/20/95 added for Radar #1193530
  1011.                 begin
  1012.                     if not (get_target_info('processor') ~= /68≈/)
  1013.                         throw "680x0 processor required (will not run on PowerPC)";
  1014.                 end;
  1015.                 
  1016.                 case 'SNConflict':
  1017.                 begin
  1018.                     #SBR 12/20/96 Changed for Radar 1615038
  1019.                     #if not AcquireApplication( appName )
  1020.                         #throw "could not acquire a lock on {appName} from the Arbitrator";
  1021.                     SNConflict := true;
  1022.                 end;
  1023.                 
  1024.                 case 'QuickTime':
  1025.                 begin
  1026.                     if not get_target_info('QuickTime#')
  1027.                         throw "QuickTime required";
  1028.                 end;
  1029.                 
  1030.                 case '32Bit':
  1031.                 begin
  1032.                     # Radar 1274923: advise to remove 32-bit unclean apps
  1033.                     if get_target_info('32#')
  1034.                         throw "32-bit unclean: please remove this test def";
  1035.                 end;
  1036.                 
  1037.                 case 'bgLaunchOK':
  1038.                 begin
  1039.                     bgLaunchOK := true;
  1040.                 end;
  1041.                 
  1042.                 case '68040 Caches':
  1043.                 begin
  1044.                     throw "68040 cache unclean: please remove this test def";
  1045.                 end;
  1046.                 
  1047.                 case 'EBBE':
  1048.                 begin
  1049.                     if get_target_info('EBBE')
  1050.                         throw "known problems with EvenBetterBusError";
  1051.                 end;
  1052.                 
  1053.                 case 'MMM':
  1054.                 begin
  1055.                     # Added for Radar 1271126
  1056.                     # 0 is original 24-bit, 1 is original 32-bit, > 1 is Modern
  1057.                     if get_target_info('heapType#') > 1
  1058.                         throw "known problems with Modern Memory Manager";
  1059.                 end;
  1060.                 
  1061.                 # if the test def is a Maxwell tier 0 app
  1062.                 case 'MaxT0':
  1063.                 begin
  1064.                     # This launchParam is in a variety of test defs... should we remove it???
  1065.                 end;
  1066.                 
  1067.                 default:    # {'bitDepth',{}} param, or not a simple string match, or unrecognized
  1068.                 begin
  1069.                     throwUp := true;
  1070.                     
  1071.                     if typeOf(launchParam) = 'list'
  1072.                     begin
  1073.                         if launchparam[1] = 'bitDepth'
  1074.                             throwUp := false;                     # just ignore this param here
  1075.                     end;
  1076.                     
  1077.                     if throwUp
  1078.                         throw "There was an invalid LaunchParam in this test definition- {launchparam}";
  1079.                 end;
  1080.             end;            # switch launchParam
  1081.         end;            # for each launchParam in launchParams
  1082.     end;            # try
  1083.     catch skipReason;
  1084.     
  1085.     if skipReason
  1086.         return {'incomplete', "Skipped '{appName}' - {skipReason}"};
  1087.  
  1088.     # At this point we are ready to launch the application by the specified method
  1089.     
  1090.     #SBR 12/20/96 Changed for Radar 1615038
  1091.     # Before launching, acquire a lock on the app if necessary
  1092.     if SNConflict
  1093.     begin
  1094.         if not AcquireApplication( appName )
  1095.             return {'incomplete', "Skipped '{appName}' - (could not acquire a lock on {appName} from the Arbitrator)"};
  1096.     end;
  1097.     
  1098.     RStatus("LaunchApplication: launching {appName} by {launchBy}", v_level);
  1099.     
  1100.     theTarget := _Match([target],false,{}); # -1105 is an error here!
  1101.  
  1102.     if not theTarget
  1103.     begin
  1104.         RAddResult("LaunchApplication: target crashed before launch");
  1105.         return badLaunch; 
  1106.     end;
  1107.     
  1108.     if launchBy ~= /agentVU≈/
  1109.     begin
  1110.         if noCreatorLaunch
  1111.             return {'incomplete', "Skipped '{appName}' - noCreatorLaunch"};
  1112.             
  1113.         if launchBy = 'agentVUFG'
  1114.         begin
  1115.             appWaitDesc := [application t:appName];
  1116.             agentVUMethod := 'into the foreground.';
  1117.         end;
  1118.         else     # launchBy = 'agentVUBG'
  1119.         begin
  1120.             if not bgLaunchOK
  1121.                 return {'incomplete', "Skipped '{appName} - it does not support background launch"};
  1122.                 
  1123.             appWaitDesc := [menuItem t:appName m:processMenu];
  1124.             agentVUMethod := 'into the background.';
  1125.         end;
  1126.  
  1127.         try
  1128.         begin
  1129.             tAgentLaunchedAppName := launch(appSig, true, launchBy = 'agentVUFG');
  1130.             RAddResult("AgentVU launched '{theActualAppName}' by creator '{appSig}' {agentVUMethod}");
  1131.         end;
  1132.         catch theError
  1133.         begin
  1134.             tAgentLaunchedAppName := "";
  1135.             switch theError
  1136.             begin
  1137.                 case -1230:
  1138.                 begin
  1139.                     RAddResult("AgentVU could not find '{appName}' by creator '{appSig}'");
  1140.                     launchBy := "Find File ('{launchBy}' could not find it)";
  1141.                 end;
  1142.                 
  1143.                 case -1231:
  1144.                 begin
  1145.                     RAddResult("AgentVU could not launch '{appName}', it may need more memory");
  1146.                     launchBy := "Find File ('{launchBy}' needs more memory)";
  1147.                 end;
  1148.                 
  1149.                 case -1096:
  1150.                 begin
  1151.                     RAddResult("Target restarted during Agent VU launch, creator '{appSig}' {agentVUMethod}");
  1152.                     #do not retry by Finder, fail the test def
  1153.                     return {'fail', "'{appName}' crashed during Agent VU launch command (-1096)"};
  1154.                 end;
  1155.                 
  1156.                 default: 
  1157.                 begin
  1158.                     RAddResult("AgentVU returned unknown error {theError} trying to launch '{appName}'");
  1159.                     launchBy := "Find File ('{launchBy}' failed for unknown reason)";
  1160.                 end;
  1161.             end;
  1162.     
  1163.             RAddResult("Retrying the launch by Find File");
  1164.         end;
  1165.     end;
  1166.     else if launchBy ~= /VUAid2≈/ 
  1167.     begin
  1168.         if launchBy = 'VUAid2FG'
  1169.         begin
  1170.             appWaitDesc := [application t:appName];
  1171.             VUAidMethod := 'into the foreground.';
  1172.         end;
  1173.         else     # launchBy = 'VUAid2BG'
  1174.         begin
  1175.             if not bgLaunchOK
  1176.                 return {'incomplete', "Skipped '{appName} - it does not support background launch"};
  1177.             appWaitDesc := [menuItem t:appName m:processMenu];
  1178.             VUAidMethod := 'into the background.';
  1179.         end;
  1180.  
  1181.         returnVal := VUAid2('launch', appName, {}, launchBy = 'VUAid2FG', true);
  1182.         if not returnVal[1]    
  1183.             RAddResult("VUAid External Tool launched '{appName}' {VUAidMethod} by name");
  1184.         else
  1185.         begin
  1186.             RAddResult("VUAid External Tool could not launch '{appName}' by name");
  1187.             return badLaunch; 
  1188.         end;
  1189.     end;
  1190.     
  1191.     
  1192.     if launchBy ~= /Find File≈/ 
  1193.     begin
  1194.         if FindFile(appName, 'name', 'is', 0, 'launch', v_level)
  1195.             RAddResult("Find File found application {appName} and launched it");
  1196.         else 
  1197.         begin
  1198.             RAddResult("Find File did not find '{appName}'.");
  1199.             
  1200.             # Quit Find File if it is still open.
  1201.             if _MatchBoolean([application t:"Find File"])
  1202.             begin
  1203.                 if _MatchBoolean([window t:'' o:1 s:dialog])
  1204.                     type_keys({returnKey});            
  1205.                 key_eq('q');
  1206.             end;
  1207.             return badLaunch; 
  1208.         end;
  1209.         appWaitDesc := [application t:appName];
  1210.     end;
  1211.     else
  1212.     begin
  1213.         if launchBy ~= /Finder≈/ 
  1214.         begin
  1215.             curAppName := _Match([application]).t;
  1216.             if curAppName <> 'Finder'
  1217.             begin
  1218.                 if not twitch('Finder')
  1219.                 begin
  1220.                     RAddResult("Could not switch to Finder, will try to quit {curAppName}");
  1221.                     abort_app(-1);
  1222.                     if not twitch('Finder')
  1223.                     begin
  1224.                         RAddResult("Could not quit {curAppName}");
  1225.                         return badLaunch; 
  1226.                     end;
  1227.                 end;
  1228.             end;
  1229.             if appDir            # check the expected 
  1230.             begin
  1231.                 findResult := find(appName,"appSysFile",,,{appDir});
  1232.                 appDirString := " inside '{appDir}'";
  1233.             end;
  1234.             else 
  1235.             begin
  1236.                 findResult := find(appName,"appSysFile");
  1237.                 appDirString := "";
  1238.             end;
  1239.             
  1240.             if not findResult 
  1241.             begin
  1242.                 RAddResult("Finder did not find '{appName}'{appDirString}");
  1243.                 key_eq('w',5);
  1244.                 return badLaunch; 
  1245.             end;
  1246.             
  1247.             key_eq('o',5);        # the actual launch with cmd-opt-o (option key) to close window
  1248.             
  1249.             RAddResult("Finder found '{appName}'{appDirString} and launched it");
  1250.             
  1251.             finderLaunchWait := 10;
  1252.             if not await_absence([application t:'Finder'],finderLaunchWait,,,6) 
  1253.             begin
  1254.                 gDialogWindow := false;
  1255.                 gOtherUnexpectedFlag := true;
  1256.                 if _MatchBoolean([window o:1 s:dialog])
  1257.                     CheckLaunchDialog(-1);
  1258.                 key_eq('w',5);
  1259.                 RAddResult("Finder was still in the foreground after {finderLaunchWait} seconds");
  1260.                 return badLaunch;
  1261.             end;
  1262.             appWaitDesc := [application t:appName];
  1263.         end;
  1264.     end;
  1265.     
  1266.     theTarget := _Match([target],false,{}); # -1105 is an error here!
  1267.  
  1268.     if not theTarget
  1269.     begin
  1270.         RAddResult("crashed during launch");
  1271.         return badLaunch;
  1272.     end;
  1273.     
  1274.     #make sure appWaitDesc appears
  1275.     if descType(appWaitDesc) = 'menuItem'                 # BG launch
  1276.     begin
  1277.         # first wait for any change in the process menu, then see if it was the right change
  1278.         endTime := get_end_time(appWait);
  1279.         try while true 
  1280.         begin
  1281.             if timed_out(endTime)
  1282.                 throw false;
  1283.             
  1284.             try
  1285.                 match [menuItem m:processMenu t:$newApList]!;    # store current items in process menu
  1286.             catch theError
  1287.                 ExceptionDispatcher(theError,,{"Match 4 in LaunchApplication", {appName, appSig, appDir, 
  1288.                                             launchBy, launchParams, appWait, v_level}});
  1289.             
  1290.             if newApList <> curApList
  1291.                 throw true;
  1292.         end;
  1293.         catch appMenuChangedInTime;
  1294.         
  1295.         if appMenuChangedInTime
  1296.         begin
  1297.             if select_descriptor(appWaitDesc, 0,6)
  1298.             begin
  1299.                 RAddResult("'{appName}' appeared in the process menu and was selected.");
  1300.             end;
  1301.             else
  1302.             begin
  1303.                 # the wrong application launched, we have to abort it.
  1304.                 
  1305.                 # find which process menu item is the wrong app
  1306.                 newApListLength := card newApList;
  1307.                 for thisMenuItem := 1 to newApListLength
  1308.                 begin
  1309.                     # use not(a=b) instead of a<>b to handle undefined when last item differs
  1310.                     # we assume newApList is longer than curApList
  1311.                     
  1312.                     if not (newApList[thisMenuItem] = curApList[thisMenuItem])
  1313.                     begin
  1314.                         badApName := newApList[thisMenuItem];
  1315.                         newApListLength := 1;
  1316.                     end;
  1317.                 end;
  1318.                 
  1319.                 twitch(badApName);
  1320.                 RAddResult("'{badApName}' unexpectedly appeared in the process menu and was selected.");
  1321.             end;
  1322.  
  1323.             # let the FG transition code do the final reporting
  1324.             appWaitDesc := [application t:appName];
  1325.         end;
  1326.         else
  1327.         begin
  1328.             RAddResult("'{appName}' did not appear in the process menu after {appWait} seconds.");
  1329.             return badLaunch;
  1330.         end;
  1331.     end;
  1332.     
  1333.     if descType(appWaitDesc) = 'application'            # FG launch, or switch to FG from BG launch
  1334.     begin
  1335.         endTime := get_end_time(appWait);
  1336.         try while true 
  1337.         begin
  1338.             if timed_out(endTime)
  1339.                 throw false;
  1340.             
  1341.             newApName := _Match([application]).t;
  1342.             if newApName <> curApName
  1343.                 throw true;
  1344.         end;
  1345.         catch frontAppChangedInTime;
  1346.         
  1347.         if frontAppChangedInTime
  1348.         begin
  1349.             if newApName <> appName
  1350.             begin
  1351.                 # the wrong application launched, we have to abort it.
  1352.                 badApName := newApName;
  1353.                 RAddResult("'{badApName}' came to the front instead of '{appName}' - aborting.");
  1354.                 RAddResult("Please throw away all but one copy of this application or add the");
  1355.                 RAddResult("    'noCreatorLaunch' parameter to its test def.");
  1356.                 abort_app(-1);
  1357.                 return badLaunch;
  1358.             end;
  1359.         end;
  1360.         else 
  1361.         begin
  1362.             if launchBy ~= /≈BG/
  1363.                 RAddResult("'{appName}' did not come to the front after selecting it in the Process menu.");
  1364.             else
  1365.                 if ((not gDialogWindow) and gItemFound)
  1366.                     RAddResult("'{appName}' did not come to the front in {appWait} seconds - it may have crashed");
  1367.  
  1368.             return badLaunch;
  1369.         end;
  1370.     end;
  1371.     
  1372.     RAddResult("'{appName}' came to the front and did not crash");
  1373.     return {'pass', launchBy};
  1374. end;
  1375.  
  1376.  
  1377. #########################################################################
  1378. #    task            CheckLaunchDialog(v_level)
  1379. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1380. #    Description:    If a dialog is displayed at launch time then this task is invoked 
  1381. #                    to analyze such dialog and decide what to do next.
  1382. #    Parameters:        currentDialog:    The current window trait from which the dialog 
  1383. #                                    will be analyzed.
  1384. #                    v_level:        verbosity level for log output
  1385. #    Returns:        internally performs the desired action depending upon the dialog
  1386. #    Example:        CheckLaunchDialog();
  1387. #    Assumptions:    VU 2.1
  1388. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1389. #    History:
  1390. #        10/17/96    Masa    Created
  1391. #        10/23/96    Masa    added code to improve treatment of unexpected dialogs
  1392. #        10/29/96    Masa    fixed matching problem in 'Get static dialog text' code segment
  1393. #        12/10/96    SBR/Masa    Changed  await_absence(previousDesc to use waitTime instead of default.
  1394. #########################################################################
  1395. task CheckLaunchDialog(v_level := 5)
  1396. begin
  1397.     RStatus("Entering CheckLaunchDialog", v_level);
  1398.     
  1399.     global  gDialogWindow;
  1400.     global    gOtherUnexpectedFlag;
  1401.  
  1402.     gDialogWindow := true;
  1403.     kMaxDialogOrd := 20;
  1404.         
  1405.     ######## GET STATIC DIALOG TEXT, IF ANY    
  1406.     ordinality :=2;
  1407.     try
  1408.         match[window t:'' o:1 s:dialog k:{[staticText o:ordinality t:?dialogStaticText]}];
  1409.     catch theError
  1410.         ExceptionDispatcher(theError,,{"Match 1 in CheckLaunchDialog", {testType, RunOnlyTheseTests, SkipTheseTests, engineParameters, v_level}});
  1411.     While ((not dialogStaticText) and (ordinality < kMaxDialogOrd))
  1412.     begin
  1413.         ordinality := ordinality +1;
  1414.         try
  1415.             match[window t:'' o:1 s:dialog k:{[staticText o:ordinality t:?dialogStaticText]}];
  1416.         catch theError
  1417.             ExceptionDispatcher(theError,,{"Match 2 in CheckLaunchDialog", {testType, RunOnlyTheseTests, SkipTheseTests, engineParameters, v_level}});
  1418.     end;
  1419.     
  1420.     ######## IF TEXT FOUND THEN ANALYZE SOME TYPICAL CASES
  1421.     If dialogStaticText
  1422.     begin
  1423.         #RAddResult('<<< Checking unexpected dialog...');
  1424.         if ((dialogStaticText ~= /≈∂n*≈memory≈∂n*≈∂n*/) or (dialogStaticText ~= /≈∂n*≈RAM≈∂n*≈∂n*/)) and
  1425.             ((dialogStaticText ~= /≈∂n*≈not≈∂n*≈∂n*/) or (dialogStaticText ~= /≈∂n*≈insufficient≈∂n*≈∂n*/))
  1426.         begin
  1427.             errDialogText := '';
  1428.             for i := 1 to (card dialogStaticText) 
  1429.             begin
  1430.                 if dialogStaticText[i] = "∂n"        # discard from carriage returns onward 
  1431.                     i := card dialogStaticText;
  1432.                 else 
  1433.                     errDialogText := errDialogText + dialogStaticText[i];
  1434.             end;
  1435.             RAddResult("unexpected dialog: {errDialogText}");
  1436.             type_keys({returnKey});
  1437.             RStatus("unexpected dialog action: pressed the return key", v_level);
  1438.         end;
  1439.         else
  1440.         begin
  1441.             if ((dialogStaticText ~= /≈∂n*≈cannot≈∂n*≈∂n*/) or (dialogStaticText ~= /≈∂n*≈Cannot≈∂n*≈∂n*/)) and 
  1442.                 (dialogStaticText ~= /≈∂n*≈start≈∂n*≈∂n*/) 
  1443.             begin
  1444.                 errDialogText := '';
  1445.                 for i := 1 to (card dialogStaticText) 
  1446.                 begin
  1447.                     if dialogStaticText[i] = "∂n"        # discard from carriage returns onward 
  1448.                         i := card dialogStaticText;
  1449.                     else 
  1450.                         errDialogText := errDialogText + dialogStaticText[i];
  1451.                 end;
  1452.                 RAddResult("unexpected dialog: {errDialogText}");
  1453.                 type_keys({returnKey});
  1454.                 RStatus("unexpected dialog action: pressed the return key", v_level);
  1455.             end;
  1456.             else
  1457.             begin
  1458.                 if (dialogStaticText ~= /≈∂n*≈server≈∂n*≈∂n*/)
  1459.                 begin
  1460.                     errDialogText := '';
  1461.                     for i := 1 to (card dialogStaticText) 
  1462.                     begin
  1463.                         if dialogStaticText[i] = "∂n"        # discard from carriage returns onward 
  1464.                             i := card dialogStaticText;
  1465.                         else 
  1466.                             errDialogText := errDialogText + dialogStaticText[i];
  1467.                     end;
  1468.                     RAddResult("unexpected dialog: {errDialogText}");
  1469.                     type_keys({returnKey});
  1470.                     RStatus("unexpected dialog action: pressed the return key", v_level);
  1471.                 end;                
  1472.                 else
  1473.                 begin
  1474.                     if (dialogStaticText ~= /≈∂n*≈256≈∂n*≈∂n*/) and 
  1475.                         ((dialogStaticText ~= /≈∂n*≈colors≈∂n*≈∂n*/) or (dialogStaticText ~= /≈∂n*≈color≈∂n*≈∂n*/))
  1476.                     begin
  1477.                         errDialogText := '';
  1478.                         for i := 1 to (card dialogStaticText) 
  1479.                         begin
  1480.                             if dialogStaticText[i] = "∂n"        # discard from carriage returns onward 
  1481.                                 i := card dialogStaticText;
  1482.                             else 
  1483.                                 errDialogText := errDialogText + dialogStaticText[i];
  1484.                         end;
  1485.                         RAddResult("unexpected dialog: {errDialogText}");
  1486.                         type_keys({returnKey});
  1487.                         RStatus("unexpected dialog action: pressed the return key", v_level);
  1488.                     end;
  1489.                     else
  1490.                     begin
  1491.                         if gOtherUnexpectedFlag
  1492.                             unexpected_dialog(,,-1);
  1493.                     end;
  1494.                 end;
  1495.             end;
  1496.         end;
  1497.     end;
  1498. end;
  1499.  
  1500.  
  1501. #########################################################################
  1502. #    task            QuitSequence(appName, theSequence, v_level)
  1503. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1504. #    Description:    Quit an application by a particular method using a custom sequence
  1505. #                    or the default sequence, unless the target is not capable of it.
  1506. #    Parameters:        appName:        Exact name of the application to quit. The 
  1507. #                                    application must already be in the foreground.
  1508. #                    theSequence:    A custom sequence (see AppSequence for details) to quit 
  1509. #                                    the application. QuitSequence appends the conditional 
  1510. #                                    {[application t:appName],[menuItem t:/Quit≈/ m:2]}
  1511. #                                    to the end of the sequence, and instructs AppSequence 
  1512. #                                    not to verify the current app during the conditional.
  1513. #                    v_level:        verbosity level for log output
  1514. #    Returns:        success: true, failure: false
  1515. #    Example:        QuitSequence('TeachText 7.0@', );
  1516. #                    AppSequence('ResEdit™ 2.1.1@', 'RSED', 'ResEdit™ 2.1.1ƒ',,
  1517. #                            {'noCreatorLaunch'},{[window s:plain],{'key_eq', 'return'}, 
  1518. #                            [staticText t:'New File Name:' w:1], {'SFPut', '@!@-ResEdit 1.1.1'},
  1519. #                            [window t:'@!@-ResEdit 1.1.1']},'Quadra700',,)
  1520. #    Assumptions:    VU 2.1
  1521. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1522. #    History:
  1523. #        ??/??/92 SBR    Created
  1524. #        02/23/94 SBR    Added quitWait value for quit timeout. It was using default 10 seconds.
  1525. #        09/03/94 SBR    Added error handling for target access.
  1526. #        04/10/95 SBR    Uses ReleaseApplication() to talk to Arbitrator.
  1527. #                        Formatted source text according to standards.
  1528. #        08/03/95 SBR    Changes for Radar 1270966, 1270963
  1529. #########################################################################
  1530. task QuitSequence(appName := '', theSequence := {}, v_level := 4)
  1531. begin
  1532.     RStatus("QuitSequence: quitting {appName}", v_level);
  1533.     badQuit := {'fail',"'{appName}' did not quit properly"};
  1534.  
  1535.     if not _MatchBoolean([application t:appName])
  1536.     begin
  1537.         RAddResult("QuitSequence: '{appName}' was not in the foreground");
  1538.         quitSeqPassed := false; 
  1539.     end;    
  1540.     else 
  1541.     begin
  1542.         theSequence :=                                         # default quit sequence
  1543.             theSequence + {{[application t:appName],[menuItem t:/Quit≈/ m:2]}};
  1544.         stopAppCheckingAt := card theSequence - 1;            # allow custom quit before default
  1545.         quitSeqPassed := AppSequence (appName, theSequence, false, stopAppCheckingAt);
  1546.     end;
  1547.     
  1548.     quitWait := 30;
  1549.  
  1550. #        if not (await_absence([menuItem t:appName],quitWait,,,6) and
  1551. #                    await_absence([application t:appName],quitWait,,,6)) 
  1552.  
  1553.     # new if clause with AwaitAppQuit(), to fix Radar 1270966 and 1270963
  1554.     appQuitStatus := AwaitAppQuit(appName, quitWait, -1);
  1555.     if isUndefined( appQuitStatus )
  1556.     begin
  1557.         RAddResult("target crashed while the application was quitting");
  1558.         badQuit[2] := badQuit[2] + " - target crashed";
  1559.         quitSeqPassed := false;
  1560.     end;
  1561.     else if not appQuitStatus
  1562.     begin
  1563.         SysBeep();
  1564.         RStatus ("AFTER TRYING TO QUIT, '{appName}' IS STILL ACTIVE. WE'RE TAKING STEPS…", 1);
  1565.         abort_app(-1);
  1566.         badQuit := {'fail',"'{appName}' did not quit within {quitwait} seconds"};
  1567.         quitSeqPassed := false;
  1568.     end;
  1569.     
  1570.     # AFTER THIS POINT, THE APP IS GUARANTEED TO BE NOT RUNNING
  1571.     
  1572.     if UsingArbitrator()
  1573.     begin
  1574.         # Un-register the app for SNConflict. If we are using the Arbitrator at all, we send 
  1575.         # every app name to ReleaseApplication() and let that task decide for us if the 
  1576.         # application is registered or not. We do this because the actual registration 
  1577.         # mechanism may change in the future, so keep it in wrapper tasks.
  1578.         # If the app was not registered, ReleaseApplication() returns true.
  1579.         
  1580.         if not ReleaseApplication( appName )
  1581.             return {'incomplete', 'QuitSequence: {appName} quit, but ReleaseApplication failed.'};
  1582.     end;
  1583.  
  1584.     # check for crash if sequence passed, Radar 1270963
  1585.     if quitSeqPassed
  1586.     begin
  1587.         theTarget := _Match([target],false,{}); # -1105 is an error here!
  1588.  
  1589.         if not theTarget
  1590.         begin
  1591.             badQuit[2] := badQuit[2] + " - target crashed";
  1592.             quitSeqPassed := false;
  1593.             RAddResult("target crashed after the application quit");
  1594.         end;
  1595.         else 
  1596.         begin
  1597.             RAddResult("target still running after the application quit");
  1598.         end;
  1599.     end;
  1600.     
  1601.     if quitSeqPassed
  1602.     begin
  1603.         RAddResult("completed quit sequence");
  1604.         return {'pass'}; 
  1605.     end;
  1606.     else 
  1607.     begin
  1608.         RAddResult("failed quit sequence");
  1609.         return badQuit; 
  1610.     end;
  1611. end;
  1612.  
  1613.  
  1614. #########################################################################
  1615. #    task        AppSequence(appName, theSequence, conditional, stopAppCheckingAt, v_level)
  1616. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1617. #    Description:    Execute a list as a sequence of wait/do items 
  1618. #    Parameters:        appName:    "": ignore application; used for a quit sequence with 
  1619. #                                    conditional save dialog (and future twitch feature)
  1620. #                                "{string}": this application must remain constant for
  1621. #                                            the entire sequence or the sequence fails.
  1622. #                        WARNING: twitching applications in a sequence is not yet supported!
  1623. #                    theSequence:    List of things to wait for and do
  1624. #                    stopAppCheckingAt:    Index in theSequence to stop checking the app,
  1625. #                                        mainly during the QuitSequence default conditional.
  1626. #                    conditional:    true if this is a conditional sequence
  1627. #                    v_level:        verbosity level for log output
  1628. #    Returns:        success: true, failure: false
  1629. #    Examples:        see AppSequence or QuitSequence; 
  1630. #    Assumptions:    VU 2.1
  1631. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1632. #    History:
  1633. #        11/07/92    SBR        Created as doSequence
  1634. #        10/10/93    SBR        Changed to AppSequence
  1635. #        04/10/95    SBR        Removed 'restart' selectAction. Added
  1636. #                            better reporting for move_mouse and type_keys. Moved
  1637. #                            code for waitItem and doItem into separate tasks. Changed
  1638. #                            descString from a constructed string to the descriptor 
  1639. #                            as it appears in the sequence. Now reports the ordinal
  1640. #                            of the sequence item that failed. 
  1641. #                            Formatted source text according to standards.
  1642. #        08/02/95    SBR        Changed default v_level from 5 to 4, Radar 1274921
  1643. #########################################################################
  1644. task AppSequence(appName, theSequence, conditional := false, stopAppCheckingAt := 32767, v_level := 4)
  1645. begin
  1646.     if conditional 
  1647.         RAddResult("BEGIN conditional");
  1648.     
  1649.     waitFor := true;
  1650.  
  1651.     for sequenceIndex := 1 to card theSequence
  1652.     begin
  1653.         thing := theSequence[sequenceIndex];
  1654.         if conditional
  1655.             indexStr := "sub-sequence item {sequenceIndex}";
  1656.         else
  1657.             indexStr := "sequence item {sequenceIndex}";
  1658.         
  1659.         if R_BeVerbose(v_level)
  1660.             RStatus("AppSequence: {indexStr} is {thing}",v_level);
  1661.         
  1662.         theTarget := _Match([target],false,{}); # -1105 is an error here!
  1663.         
  1664.         if not theTarget
  1665.         begin
  1666.             RAddResult("AppSequence: target crashed at {indexStr}");
  1667.             return false;
  1668.         end;
  1669.  
  1670.         if appName and (sequenceIndex < stopAppCheckingAt)
  1671.         begin
  1672.             if typeOf(thing) = 'string'                    #Do not do app check if the next
  1673.                 isNotErrorString := card(thing) <= 1;    #item is an error string, we may have
  1674.             else 
  1675.                 isNotErrorString := false;                #made the app go away on purpose.
  1676.             
  1677.             if (theTarget.a[1].t <> appName) AND isNotErrorString
  1678.             begin
  1679.                 RAddResult("application disappeared at {indexStr} - it may have crashed");
  1680.                 return false;
  1681.             end;
  1682.         end;
  1683.     
  1684.         if typeOf(thing) = 'descriptor'         # convert descriptor to loggable string
  1685.         begin
  1686. #                thingType := descType(thing);
  1687. #                            
  1688. #                thingName := thing.t; 
  1689. #                if isUndefined( thingName )
  1690. #                    thingName := '';
  1691. #                else 
  1692. #                    thingName := " t:'{thingName}'";
  1693. #                
  1694. #                thingOrdinality := '';
  1695. #                if thing ~= [contentItem] OR isMember(thingType, { 'menu', 'menuItem', 'window'})
  1696. #                begin
  1697. #                    thingOrdinality := thing.o; 
  1698. #                    if isUndefined( thingOrdinality )
  1699. #                        thingOrdinality := '';
  1700. #                    else
  1701. #                        thingOrdinality := " o:'{thingOrdinality}'";
  1702. #                end;
  1703. #                
  1704. #                windowStyle := '';
  1705. #                if thingType = 'window'
  1706. #                begin
  1707. #                    switch thing.s
  1708. #                    begin
  1709. #                        case dialog:
  1710. #                            windowStyle := ' s:dialog';
  1711. #                        case document:
  1712. #                            windowStyle := ' s:document';
  1713. #                        case da:
  1714. #                            windowStyle := ' s:da';
  1715. #                        case plain:
  1716. #                            windowStyle := ' s:plain';
  1717. #                        case shadow:
  1718. #                            windowStyle := ' s:shadow';
  1719. #                    end;
  1720. #                end;
  1721. #                descString := "[{thingType}{thingName}{thingOrdinality}{windowStyle}]";
  1722.             descString := "{thing}";
  1723.         end;
  1724.             
  1725. ###    WAIT ITEM
  1726.         if waitFor
  1727.         begin
  1728.             try 
  1729.             begin
  1730.                 previousThing := thing;                    # if we want to select it later
  1731.                 LQWaitItem( { appName, thing, conditional, sequenceIndex, stopAppCheckingAt }, v_level );
  1732.             end;
  1733.             catch theWaitInterruption
  1734.             begin
  1735.                 return theWaitInterruption;
  1736.             end;
  1737.         end;
  1738.  
  1739. ###    DO ITEM
  1740.         else begin
  1741.             try 
  1742.             begin
  1743.                 LQDoItem( { thing, previousThing }, v_level );
  1744.             end;
  1745.             catch theDoInterruption
  1746.             begin
  1747.                 return theDoInterruption;
  1748.             end;
  1749.         end;
  1750.         
  1751.         waitFor := not waitFor;
  1752.     end;    # for each thing in theSequence
  1753.     
  1754.     if conditional 
  1755.         RAddResult("END conditional (passed)");
  1756.     return true;
  1757. end;
  1758.  
  1759.  
  1760. #########################################################################
  1761. #    task            LQWaitItem(waitInfoList, v_level)
  1762. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1763. #    Description:    Waits for an item to appear or does something else passively.
  1764. #    Parameters:        waitInfoList:        list containing info for waiting
  1765. #                        { appName, thing, conditional, sequenceIndex, stopAppCheckingAt }
  1766. #                    v_level:             verbosity level for reporting
  1767. #    Returns:        nothing (throws true or false to support sub-sequence recursion)
  1768. #    Example:        try LQWaitItem({appName,thing,conditional,sequenceIndex,stopAppCheckingAt});
  1769. #                    catch theWaitInterruption
  1770. #                        return theWaitInterruption
  1771. #    Assumptions:    VU 2.1
  1772. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1773. #    History:
  1774. #        02/25/95    SBR        created by moving code from appSequence()
  1775. #        07/30/95    SBR        Use GetLQWaitItemTimeout() for Radar 1274920
  1776. #                            Fix for Radar 1272949.
  1777. #########################################################################
  1778. task    LQWaitItem( waitInfoList, v_level := 4)
  1779. begin
  1780.     appName := waitInfoList[1];
  1781.     thing := waitInfoList[2];
  1782.     conditional := waitInfoList[3];
  1783.     sequenceIndex := waitInfoList[4];
  1784.     stopAppCheckingAt := waitInfoList[5];
  1785.     
  1786.     switch typeOf(thing)
  1787.     begin
  1788.         case 'descriptor':
  1789.         begin
  1790.             # fix for Radar 1274920
  1791.             waitTime := GetLQWaitItemTimeout( thing, conditional, v_level);
  1792. #                if conditional 
  1793. #                begin
  1794. #                    if (descType(thing) = 'application')    # adjust time for type of awaitItem
  1795. #                        waitTime := 2;
  1796. #                    else 
  1797. #                        waitTime := 10;
  1798. #                end;
  1799. #                else 
  1800. #                    waitTime := 150;
  1801.                 
  1802.             if await_presence(thing,waitTime,,,6)
  1803.                 RAddResult("{thing} present");
  1804.             else 
  1805.             begin
  1806.                 RAddResult("{thing} not present after {waitTime} seconds");
  1807.                 if conditional 
  1808.                 begin
  1809.                     #if thing = theSequence[1]
  1810.                     if sequenceIndex = 1
  1811.                     begin
  1812.                         ##SBR Debug stuff
  1813. #                            global gWastedTime := gWastedTime + waitTime;
  1814. #                            println "        ••Conditional Timeout - wasted {waitTime} seconds! (total {gWastedTime})••";
  1815.                         
  1816.                         throw RAddResult("END conditional (ignored)");
  1817.                     end; 
  1818.                     else 
  1819.                         throw not RAddResult("END conditional (failed)");
  1820.                 end;
  1821.                 else 
  1822.                     throw false;
  1823.             end;
  1824.         end;
  1825.  
  1826.         case 'integer':
  1827.         begin
  1828.             wait(thing);
  1829.             RAddResult("waited {thing} seconds");
  1830.         end;
  1831.  
  1832.         case 'list':
  1833.         begin
  1834.             if sequenceIndex < stopAppCheckingAt 
  1835.             begin
  1836.                 # to fix Radar 1272949; special conditional waits until app quits
  1837.                 # we have to stop checking for the app when it quits!
  1838.                 if thing = {[application t:appName],'>'}
  1839.                     subSequenceStopAppCheckAt := 0;
  1840.                 else
  1841.                     subSequenceStopAppCheckAt := 32767;
  1842.             end; 
  1843.             else 
  1844.                 subSequenceStopAppCheckAt := 0;
  1845.                 
  1846.             if not AppSequence(appName, thing, true, subSequenceStopAppCheckAt) 
  1847.                 throw false;
  1848.         end;
  1849.         
  1850.         case 'string':                        # empty string means don't wait for anything
  1851.         begin
  1852.             if thing                        # non-empty string means log it as a failure report
  1853.                 throw not RAddResult("sequence failed because: {thing}");
  1854.         end;
  1855.     end;
  1856. end;
  1857.  
  1858.  
  1859. #########################################################################
  1860. #    task            GetLQWaitItemTimeout( waitDesc, conditional, v_level )
  1861. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1862. #    Description:    Determines the time to wait for a descriptor. 
  1863. #                    If gDevelopmentMode is true, the non-conditional timeout is short.
  1864. #    Parameters:        waitDesc:         the descriptor to wait for
  1865. #                    conditional:     Boolean true:    this a conditional wait item
  1866. #                                             false:    this a normal wait item
  1867. #                    v_level:             verbosity level for reporting
  1868. #    Returns:        number of seconds to wait for the item
  1869. #    Example:        GetLQWaitItemTimeout
  1870. #    Assumptions:    VU 2.1, gDevelopmentMode = true if using Dev Launchquits
  1871. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1872. #    History:
  1873. #        07/30/95    SBR        created to fix for Radar 1274920
  1874. #########################################################################
  1875. task    GetLQWaitItemTimeout( waitDesc, conditional, v_level := 4)
  1876. begin
  1877.     global gDevelopmentMode;
  1878.     
  1879.     if conditional 
  1880.     begin
  1881.         if (descType(waitDesc) = 'application')    # adjust time for type of awaitItem
  1882.             waitTime := 2;
  1883.         else 
  1884.             waitTime := 10;
  1885.     end;
  1886.     else 
  1887.     begin
  1888.         if gDevelopmentMode
  1889.             waitTime := 10;
  1890.         else
  1891.             waitTime := 150;
  1892.     end;
  1893.     return waitTime;
  1894. end;
  1895.  
  1896.  
  1897. #########################################################################
  1898. #    task            LQDoItem(doInfoList, v_level)
  1899. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1900. #    Description:    Selects or does some other action.
  1901. #    Parameters:        doInfoList:            list containing info for doing something
  1902. #                        { thing, previousDesc }
  1903. #                    v_level:             verbosity level for reporting
  1904. #    Returns:        nothing (throws true or false to support sub-sequence recursion)
  1905. #    Example:        try LQDoItem({appName,thing,conditional,sequenceIndex,stopAppCheckingAt});
  1906. #                    catch theDoInterruption
  1907. #                        return theDoInterruption
  1908. #    Assumptions:    VU 2.1
  1909. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1910. #    History:
  1911. #        02/25/95    SBR        created by moving code from appSequence
  1912. #        02/25/95    SBR        removed support for restarting in the sequence
  1913. #########################################################################
  1914. task    LQDoItem(doInfoList, v_level := 4)
  1915. begin
  1916.     thing := doInfoList[1];
  1917.     previousDesc := doInfoList[2];
  1918.     
  1919.     switch typeOf(thing)
  1920.     begin
  1921.         case 'descriptor':
  1922.         begin
  1923.             temp := select_descriptor(thing,,5);
  1924.             if temp
  1925.                 RAddResult("{thing} selected");                
  1926.             else
  1927.                 throw not RAddResult("{thing} not selected");
  1928.         end;
  1929.  
  1930.         case 'string': 
  1931.         begin
  1932.             switch thing
  1933.             begin
  1934.                 case '':;                                # empty string means don't do anything
  1935.                 
  1936.                 case '<':                                 # select the desc we just waited for
  1937.                 begin
  1938.                     if select_descriptor(previousDesc, 0)
  1939.                         RAddResult("{previousDesc} selected");                
  1940.                     else
  1941.                         throw not RAddResult("{previousDesc} not selected");
  1942.                 end;
  1943.                 
  1944.                 case '>':                                 # awaitAbsence the desc we just waited for
  1945.                 begin
  1946.                     waitTime := GetLQWaitItemTimeout( previousDesc, false, v_level);
  1947.                     if await_absence(previousDesc,waitTime,,,6)
  1948.                         RAddResult("{previousDesc} absent");                
  1949.                     else
  1950.                         throw not RAddResult("{previousDesc} not absent");
  1951.                 end;
  1952.                 
  1953.                 default:                                # log the string as a failure report
  1954.                 begin
  1955.                     throw not RAddResult("sequence failed because: {thing}");                
  1956.                 end;
  1957.             end;
  1958.         end;
  1959.  
  1960.         case 'integer': 
  1961.         begin
  1962.             wait(thing);
  1963.             RAddResult("waited {thing} seconds");
  1964.         end;
  1965.  
  1966.         case 'list':                                # flexible selection operator
  1967.         begin
  1968.             selectAction := thing[1];
  1969.             
  1970.             switch selectAction
  1971.             begin
  1972.                 case 'type_keys':                    # type something
  1973.                 begin
  1974.                     tkList := thing[2];
  1975.                     oldSpeed := typeSpeed(50);
  1976.                     type_keys(tkList);
  1977.                     typeSpeed(oldSpeed);
  1978.                     RAddResult("type_keys: {tkList}");
  1979.                 end;
  1980.                 
  1981.                 case 'fieldSequence':                 # enter data in tab-seperated fields
  1982.                 begin
  1983.                     fsList := thing[2];
  1984.                     for each fieldEntry in fsList begin
  1985.                         oldSpeed := typeSpeed(50);
  1986.                         type_keys({fieldEntry, tabKey});
  1987.                         RAddResult("typed '{fieldEntry}' into a field, then auto-tabKey");
  1988.                         typeSpeed(oldSpeed);
  1989.                     end;
  1990.                 end;
  1991.                 
  1992.                 case 'key_eq':                      # do a command-key equivalent
  1993.                 begin
  1994.                     typeChars := thing[2];
  1995.                     key_eq(typeChars);
  1996.                     RAddResult("typed '{typeChars}' with command key down"); 
  1997.                 end;
  1998.                 
  1999.                 case 'SFGet':                         # do a generic SFGet dialog
  2000.                 begin
  2001.                     typeChars := thing[2];
  2002.                     type_keys({typeChars, returnKey});
  2003.                     RAddResult("typed '{typeChars}' then returnKey in SFGet"); 
  2004.                 end;
  2005.                 
  2006.                 case 'SFPut':                         # do a generic SFPutFile,    
  2007.                 begin                                # replace if necessary
  2008.                     typeChars := thing[2];
  2009.                     type_keys({typeChars, returnKey});
  2010.                     RAddResult("typed '{typeChars}' then returnKey in SFPut"); 
  2011.                     if select_descriptor([button t:'Replace'], 2, 6)
  2012.                         RAddResult("'{typeChars}' already existed, selected [button t:'Replace']");                
  2013.                 end;
  2014.                 
  2015.                 case 'SFPutNewName':                 # do a generic SFPutFile,
  2016.                 begin                                # do not replace, make a new name
  2017.                     typeChars := thing[2];
  2018.                     type_keys({typeChars, returnKey});
  2019.                     RAddResult("typed '{typeChars}' then returnKey in SFPutNewName");
  2020.                     newFileName := typeChars;
  2021.                     while await_presence([button t:'Replace' w:1],2,,,6)
  2022.                     begin
  2023.                         RAddResult("'{newFileName}' already existed");                
  2024.                         select_descriptor([button t:'Cancel' w:1],2,6);
  2025.                         randNew := random();
  2026.                         newFileName := "{typeChars} {randNew}";
  2027.                         type_keys({newFileName, returnKey});
  2028.                         RAddResult("typed '{newFileName}' then returnKey in SFPutNewName");
  2029.                     end;
  2030.                 end;
  2031.                 
  2032.                 case 'move_mouse':
  2033.                 begin
  2034.                     mmList := thing[2];
  2035.                     move_mouse(mmList);
  2036.                     RAddResult("move_mouse: {mmList}");
  2037.                 end;
  2038.                 
  2039.                 default:
  2040.                 begin
  2041.                     throw not RAddResult("'{selectAction}' is not a known thing to do");
  2042.                 end;
  2043.             end;    # switch selectAction
  2044.         end;        # case 'list'
  2045.     end;            # switch typeOf(thing)
  2046. end;
  2047.  
  2048.  
  2049. #########################################################################
  2050. #    task            Quit_Apps(appNames, appNamesAreExceptions, v_level)
  2051. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2052. #    Description:    Quits the specified applications in the fastest possible manner. 
  2053. #                    (To quit only the front application, use the abort_app() task).
  2054. #    Parameters:        appNames:    list of exact application names
  2055. #                    appNamesAreExceptions:    
  2056. #                        true:    quit all except Finder and apps in the list
  2057. #                        false:    quit all apps in appNames
  2058. #                    v_level:    verbosity level for log output
  2059. #    Returns:        nothing (will not return until successful)
  2060. #    Assumptions:    VU 2.1
  2061. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2062. #    History:
  2063. #        02/12/93    SBR        Created
  2064. #        08/02/95    SBR        Changes to fix Radar 1270966
  2065. #########################################################################
  2066. task Quit_Apps(appNames := {}, appNamesAreExceptions := false, v_level := 4)
  2067. begin
  2068.     global  gDialogWindow;
  2069.     global    gOtherUnexpectedFlag;
  2070.  
  2071.     if appNamesAreExceptions
  2072.     begin
  2073.         done := false;
  2074.         showedAll := false;
  2075.         
  2076.         while not done
  2077.         begin
  2078.             currentApp:= _Match ([application]).t;
  2079.     
  2080.             RStatus("Quit_Apps: Current app is '{currentApp}'.", v_level);
  2081.  
  2082.             if currentApp <> 'Finder'
  2083.             begin
  2084.                 if not isMember(currentApp, appNames)
  2085.                     abort_app();
  2086.                 else 
  2087.                 begin
  2088.                     gDialogWindow := false;
  2089.                     gOtherUnexpectedFlag := true;
  2090.                     if _MatchBoolean([window o:1 s:dialog])
  2091.                         CheckLaunchDialog(-1);
  2092.  
  2093.                     if not twitch(Finder)
  2094.                         RStatus ("Quit_Apps: Can not switch to the Finder from {currentApp}.", 1);
  2095.                         
  2096.                     myWaitVal:= GetLQWaitItemTimeout([application t:currentApp], false);
  2097.                     await_absence([application t:currentApp], myWaitVal);
  2098.                 end;
  2099.             end;
  2100.             else 
  2101.             begin                        #we are in the Finder
  2102.                 gDialogWindow := false;
  2103.                 gOtherUnexpectedFlag :=true;
  2104.                 if _MatchBoolean([window o:1 s:dialog])
  2105.                     CheckLaunchDialog(-1);
  2106.  
  2107.                 try
  2108.                     match[menuItem o:1 t:'Hide Finder' m:[menu o:?processMenu]];
  2109.                 catch theError
  2110.                     ExceptionDispatcher(theError,,{"Match 1 in Quit_Apps", {appNames, appNamesAreExceptions, v_level}});
  2111.  
  2112.                 if not showedAll
  2113.                 begin
  2114.                     if _MatchBoolean([menuItem t:'Show All' m:processMenu e:true], true)        ## do an exact match
  2115.                         _SelectBoolean([menuItem t:'Show All' m:processMenu e:true], true);        ## do an exact select
  2116.                     showedAll := true;
  2117.                 end;
  2118.                 
  2119.                 # Here, o:6 m:processMenu would indicate that something other than the finder
  2120.                 # is in the process menu. This part of the script could break if process menu
  2121.                 # ordinalities change
  2122.                 
  2123.                 if _MatchBoolean([menuItem o:6 m:processMenu])
  2124.                 begin
  2125.                     select_descriptor([menuItem t:'Hide Finder' m:processMenu]);
  2126.                     await_absence([application t:'Finder']);
  2127.                     abort_app();
  2128.                 end;
  2129.                 else 
  2130.                     done := true;
  2131.             end;
  2132.         end;
  2133.     end;
  2134.     else while appNames
  2135.     begin
  2136.         gDialogWindow := false;
  2137.         gOtherUnexpectedFlag := true;
  2138.         if _MatchBoolean([window o:1 s:dialog])
  2139.             CheckLaunchDialog(-1);
  2140.  
  2141.         currentApp := _Match ([application]).t;
  2142.  
  2143.         appIndex := isMember(currentApp,appNames);
  2144.         if appIndex
  2145.         begin
  2146.             abort_app();
  2147.             appNames := remove(appIndex, appNames);
  2148.         end;
  2149.         else 
  2150.         begin
  2151.             appToQuit := appNames[1];
  2152.             # begin new code for Radar 1270966
  2153.             try 
  2154.                 match [menu o:$menuOrds];
  2155.             catch theError
  2156.                 ExceptionDispatcher(theError,,{"Match 2 in Quit_Apps", {appNames, appNamesAreExceptions, v_level}});
  2157.  
  2158.             processMenu := menuOrds[card menuOrds];
  2159.             # end new code for Radar 1270966
  2160.  
  2161.             if select_menuItem(appToQuit,processMenu)
  2162.             begin
  2163.                 if await_presence([application t:appToQuit],,,,6)
  2164.                     abort_app();
  2165.                 else 
  2166.                     RIncomplete("Quit_Apps: {appToQuit} did not appear in front after app menu selection.", v_level);
  2167.             end;
  2168.             else 
  2169.                 RIncomplete("Quit_Apps: {appToQuit} is not in front or in the application menu.", v_level);
  2170.             appNames := remove(1, appNames);
  2171.         end;
  2172.     end;
  2173. end;
  2174.  
  2175.  
  2176. #########################################################################
  2177. #    task            AwaitAppQuit( pAppName, pTimeout, v_level )
  2178. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2179. #    Description:    Ensures an application has quit within the specified timeout. 
  2180. #                    Does NOT take any action to quit, merely verifies it is not
  2181. #                    in the foreground or background.
  2182. #    Parameters:        pAppName:         string name of the application
  2183. #                    pTimeLimit:     seconds to wait before failing
  2184. #                    v_level:     verbosity level for reporting
  2185. #    Returns:        true: application quit within pTimeLimit seconds
  2186. #                    false: application did not quit within pTimeLimit seconds
  2187. #                    undefined: target crashed or other unexpected ScriptError()
  2188. #    Example:        appName := "SimpleText";
  2189. #                    if not AwaitAppQuit( appName )
  2190. #                        RError("Application {appName} did not quit");
  2191. #    Assumptions:    VU 2.1
  2192. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2193. #    History:
  2194. #        08/02/95    SBR        created to fix Radar 1270966
  2195. #########################################################################
  2196. task    AwaitAppQuit( pAppName, pTimeLimit := 10, v_level := 4)
  2197. begin
  2198.     wait_end := get_end_time(pTimeLimit);        # Reset the time limit timer
  2199.  
  2200.     try while true
  2201.     begin
  2202.         appInForeground := _matchBoolean([application t:pAppName], true);
  2203.         
  2204.         # check for error, e.g. crash
  2205.         if isUndefined(appInForeground)
  2206.             throw undefined;
  2207.         
  2208.         if not appInForeground
  2209.         begin
  2210.             try 
  2211.                 match [menu o:$menuOrds];
  2212.             catch theError
  2213.             begin
  2214.                 ExceptionDispatcher(theError,,{"Match 1 in AwaitAppQuit", {pAppName, pTimeLimit, v_level}});
  2215.                 throw undefined;
  2216.             end;
  2217.             
  2218.             processMenu := menuOrds[card menuOrds];
  2219.             appInBackground := _matchBoolean([menuItem t:pAppName m:processMenu], true);
  2220.  
  2221.             # check for error, e.g. crash
  2222.             if isUndefined(appInBackground)
  2223.                 throw undefined;
  2224.  
  2225.             if not appInBackground
  2226.                 throw true;
  2227.         end;
  2228.  
  2229.         if timed_out(wait_end)
  2230.         begin
  2231.             RIncomplete("AwaitAppQuit: {pAppName} did not quit in {pTimeLimit} seconds",v_level);
  2232.             throw false;
  2233.         end;
  2234.     end;
  2235.     catch theResult;
  2236.  
  2237.     return theResult;
  2238. end;
  2239.  
  2240.  
  2241. #########################################################################
  2242. #    task            AcquireApplication(appName, v_level)
  2243. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2244. #    Description:    Uses the Arbitrator to reserve an application for exclusive use.
  2245. #                    See the Arbitrator Script for more explanations.
  2246. #    Parameters:        appName:    The exact string name of the application test def.
  2247. #                    v_level:     verbosity level for reporting
  2248. #    Returns:        true if successful, false if not
  2249. #    Examples:        RegisterApplication('4th Dimension 2.2.3@')
  2250. #    Assumptions:    VU 2.1
  2251. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2252. #    History:
  2253. #        01/14/94    SBR        Created as RegisterApplication
  2254. #        09/29/94    SBR        Changed to use Arbitrator external tool
  2255. #        02/20/95    SBR        Changed to AcquireApplication, uses AcquireID()
  2256. #########################################################################
  2257. task    AcquireApplication(appName, v_level := 2)
  2258. begin
  2259.     global gAcquiredApps;
  2260.     acquireWaitTime := 60;
  2261.     totalWaitTime := 0;
  2262.     
  2263.     if isUndefined(gAcquiredApps)
  2264.         gAcquiredApps := {};
  2265.     
  2266.     appIsRegistered := false;
  2267.     
  2268.     while not appIsRegistered            #loop here until app becomes available
  2269.     begin
  2270.         appIsRegistered := AcquireID( {'application', appName} );
  2271.  
  2272.         if not appIsRegistered
  2273.         begin
  2274.             if totalWaitTime = 0
  2275.                 RStatus("Waiting to use {appName} because it is in use somewhere else.",v_level);
  2276.             wait(acquireWaitTime);
  2277.             totalWaitTime := totalWaitTime + acquireWaitTime;
  2278.         end;
  2279.         else begin
  2280.             gAcquiredApps := gAcquiredApps + {appName};
  2281.             if totalWaitTime <> 0
  2282.                 RStatus("After {totalWaitTime} seconds, {appName} became available.",v_level);
  2283.         end;
  2284.     end;
  2285.     return true;
  2286. end;
  2287.  
  2288.  
  2289. #########################################################################
  2290. #    task            ReleaseApplication(appName, v_level)
  2291. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2292. #    Description:    Uses the Arbitrator to make an application available for other scripts.
  2293. #                    See the Arbitrator Script for more explanations.
  2294. #    Parameters:        appName:    The exact string name of the application test def.
  2295. #                    v_level:     verbosity level for reporting
  2296. #    Returns:        true if successful, false if not
  2297. #    Examples:        ReleaseApplication('4th Dimension 2.2.3@')
  2298. #    Assumptions:    VU 2.1
  2299. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2300. #    History:
  2301. #        01/14/94    SBR        Created as UnRegisterApplication
  2302. #        09/29/94    SBR        Changed to use Arbitrator external tool
  2303. #        02/20/95    SBR        Changed to ReleaseApplication, uses ReleaseID()
  2304. #########################################################################
  2305. task    ReleaseApplication(appName, v_level := 5)
  2306. begin
  2307.     global gAcquiredApps;
  2308.     
  2309.     if isUndefined(gAcquiredApps)
  2310.         gAcquiredApps := {};
  2311.     
  2312.     appIsRegistered := isMember(appName, gAcquiredApps);
  2313.     if appIsRegistered                    # we have acquired this app
  2314.     begin
  2315.         releaseStatus := ReleaseID( {'application',appName} );
  2316.         
  2317.         if releaseStatus
  2318.         begin
  2319.             gAcquiredApps := remove(appIsRegistered, gAcquiredApps);
  2320.             return true;
  2321.         end;
  2322.         else begin
  2323.             RIncomplete("ReleaseApplication: Arbitrator failed to release: {arbResponse}.",v_level);
  2324.             return false;
  2325.         end;
  2326.     end;
  2327.     else begin
  2328.         return true;                    # if it was never acquired, it is released!
  2329.     end;
  2330. end;
  2331.  
  2332.  
  2333.